Skip to content

Commit 14c2574

Browse files
committed
Parsing: introduce @_preInverseGenericsExceptCopyable as an alias attribute
We need an alias since `@_preInverseGenerics(except: ...)` has custom parsing that older compilers aren't designed to handle. Only simple decl attributes are parsed correctly by older compilers, so this alias allows you to write this: ``` @_preInverseGenericsExceptCopyable var x = 0 var x = 0 ``` Which all helps with the introduction of Span<~Escapable>. related to rdar://176395527
1 parent 27ba7be commit 14c2574

7 files changed

Lines changed: 53 additions & 6 deletions

File tree

include/swift/AST/DeclAttr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ DECL_ATTR(_preInverseGenerics, PreInverseGenerics,
836836
OnAbstractFunction | OnSubscript | OnVar | OnExtension,
837837
UserInaccessible | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove | UnconstrainedInABIAttr,
838838
158)
839+
DECL_ATTR_ALIAS(_preInverseGenericsExceptCopyable, PreInverseGenerics)
839840

840841
// Declares that a struct contains "sensitive" data. It enforces that the contents of such a struct value
841842
// is zeroed out at the end of its lifetime. In other words: the content of such a value is not observable

lib/AST/Attr.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,8 +1712,19 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
17121712

17131713
case DeclAttrKind::PreInverseGenerics: {
17141714
auto *attr = cast<PreInverseGenericsAttr>(this);
1715-
Printer.printAttrName("@_preInverseGenerics");
17161715
Type exceptTy = attr->getResolvedExceptType(D);
1716+
auto *pct = exceptTy->castTo<ProtocolCompositionType>();
1717+
1718+
// To avoid condfails during Span<~Escapable> adoption, emit
1719+
// `@_preInverseGenericsExceptCopyable` instead of
1720+
// `@_preInverseGenerics(except: ~Copyable)`.
1721+
if (pct->getInverses() ==
1722+
InvertibleProtocolSet({InvertibleProtocolKind::Copyable})) {
1723+
Printer.printAttrName("@_preInverseGenericsExceptCopyable");
1724+
break;
1725+
}
1726+
1727+
Printer.printAttrName("@_preInverseGenerics");
17171728
// Avoid printing `@_preInverseGenerics(except: Any)` despite that being the
17181729
// meaning of the no-arg version. It's rejected as it can confuse people.
17191730
if (exceptTy->getCanonicalType() != D->getASTContext().TheAnyType) {

lib/Parse/ParseDecl.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2745,9 +2745,18 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
27452745

27462746
case DeclAttrKind::PreInverseGenerics: {
27472747
TypeRepr *exceptType = nullptr;
2748+
Type resolvedExceptType;
27482749
SourceLoc rParenLoc = Loc;
27492750

2750-
if (consumeIfAttributeLParen()) {
2751+
// The @_preInverseGenericsExceptCopyable spelling is a shorthand for
2752+
// @_preInverseGenerics(except: ~Copyable) to avoid condfails during the
2753+
// Span<~E> adoption.
2754+
//
2755+
// We inject the resolved 'except:' type directly into the attribute.
2756+
if (AttrName == "_preInverseGenericsExceptCopyable") {
2757+
resolvedExceptType = ProtocolCompositionType::getInverseOf(
2758+
Context, InvertibleProtocolKind::Copyable);
2759+
} else if (consumeIfAttributeLParen()) {
27512760
if (Tok.getText() != "except" || peekToken().isNot(tok::colon)) {
27522761
diagnose(Tok, diag::attr_pre_inverse_generics_expected_except);
27532762
skipUntil(tok::r_paren);
@@ -2772,7 +2781,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
27722781
if (!DiscardAttribute)
27732782
Attributes.add(new (Context) PreInverseGenericsAttr(
27742783
AtLoc, SourceRange(AtLoc.isValid() ? AtLoc : Loc, rParenLoc),
2775-
exceptType));
2784+
exceptType, resolvedExceptType));
27762785
break;
27772786
}
27782787

test/ModuleInterface/pre_inverse_generics_except.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
// RUN: %FileCheck --implicit-check-not '#if' %s < %t/Test.swiftinterface
77

8+
// RUN: %target-swift-typecheck-module-from-interface(%t/Test.swiftinterface)
9+
810
// REQUIRES: swift_feature_PreInverseGenericsExcept
911

1012
// The bare @_preInverseGenerics needs no feature guard.
@@ -16,11 +18,17 @@ public func bare<T: ~Copyable>(_ t: borrowing T) {}
1618
// Older compilers that don't support the feature will not see the declaration.
1719

1820
// CHECK: #if compiler(>=5.3) && $PreInverseGenericsExcept
19-
// CHECK-NEXT: @_preInverseGenerics(except: ~Copyable) public func exceptCopyable<T>(_ t: borrowing T) where T : ~Copyable, T : ~Escapable
21+
// CHECK-NEXT: @_preInverseGenericsExceptCopyable public func exceptCopyable<T>(_ t: borrowing T) where T : ~Copyable, T : ~Escapable
2022
// CHECK-NEXT: #endif
2123
@_preInverseGenerics(except: ~Copyable)
2224
public func exceptCopyable<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
2325

26+
// CHECK: #if compiler(>=5.3) && $PreInverseGenericsExcept
27+
// CHECK-NEXT: @_preInverseGenericsExceptCopyable public func exceptCopyable2<T>(_ t: borrowing T) where T : ~Copyable, T : ~Escapable
28+
// CHECK-NEXT: #endif
29+
@_preInverseGenericsExceptCopyable
30+
public func exceptCopyable2<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
31+
2432
// CHECK: #if compiler(>=5.3) && $PreInverseGenericsExcept
2533
// CHECK-NEXT: @_preInverseGenerics(except: ~Escapable) public func exceptEscapable<T>(_ t: borrowing T) where T : ~Copyable, T : ~Escapable
2634
// CHECK-NEXT: #endif
@@ -36,7 +44,7 @@ public func exceptBoth<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
3644
@frozen
3745
public struct MySpan<T: ~Copyable & ~Escapable>: ~Copyable {
3846
// CHECK: #if compiler(>=5.3) && $PreInverseGenericsExcept
39-
// CHECK-NEXT: @_preInverseGenerics(except: ~Copyable) public var _count: Swift::Int
47+
// CHECK-NEXT: @_preInverseGenericsExceptCopyable public var _count: Swift::Int
4048
// CHECK-NEXT: #endif
4149
@_preInverseGenerics(except: ~Copyable)
4250
public var _count: Int

test/SILGen/mangling_inverse_generics.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,12 @@ public func keepEscapable<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
378378
@_preInverseGenerics
379379
public func stripBoth<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
380380

381+
// The shorthand alias mangles identically to `(except: ~Copyable)`.
382+
// DEMANGLED: test.keepCopyableShorthand<A where A: ~Swift.Copyable>(A) -> ()
383+
// CHECK: sil [ossa] @$s4test21keepCopyableShorthandyyxRi_zlF : $@convention(thin) <T where T : ~Copyable, T : ~Escapable> (@in_guaranteed T) -> () {
384+
@_preInverseGenericsExceptCopyable
385+
public func keepCopyableShorthand<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
386+
381387

382388
public struct F<T: ~Copyable>: ~Copyable {
383389
// DEMANGLED: (extension in test):test.F< where A: ~Swift.Copyable>.memberKeepCopyable() -> ()
@@ -406,6 +412,11 @@ public struct MySpan<T: ~Copyable & ~Escapable>: ~Copyable, ~Escapable {
406412
@_preInverseGenerics(except: ~Copyable)
407413
public var _count: Int
408414

415+
// DEMANGLED: (extension in test):test.MySpan< where A: ~Swift.Copyable>._count2.getter : Swift.Int
416+
// CHECK: sil [transparent] [serialized] [ossa] @$s4test6MySpanVAARi_zrlE7_count2Sivg : $@convention(method) <T where T : ~Copyable, T : ~Escapable> (@guaranteed MySpan<T>) -> Int {
417+
@_preInverseGenericsExceptCopyable
418+
public var _count2: Int
419+
409420
// DEMANGLED: (extension in test):test.MySpan< where A: ~Swift.Copyable>._pointer.getter : Swift.UnsafeRawPointer?
410421
// CHECK: sil [transparent] [serialized] [ossa] @$s4test6MySpanVAARi_zrlE8_pointerSVSgvg : $@convention(method) <T where T : ~Copyable, T : ~Escapable> (@guaranteed MySpan<T>) -> Optional<UnsafeRawPointer> {
411422
@_preInverseGenerics(except: ~Copyable)
@@ -436,4 +447,3 @@ extension MySpan where T: ~Copyable & ~Escapable {
436447
// CHECK: sil [ossa] @$s4test6MySpanVAARi_zRi0_zrlE9extMethodyyF : $@convention(method) <T where T : ~Copyable, T : ~Escapable> (@guaranteed MySpan<T>) -> () {
437448
public func extMethod() {}
438449
}
439-

test/Sema/preInverseGenerics.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ func bare<T: ~Copyable>(_ t: borrowing T) {}
88
@_preInverseGenerics(except: ~Copyable)
99
func exceptCopyable<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
1010

11+
// Shorthand alias for `@_preInverseGenerics(except: ~Copyable)`.
12+
@_preInverseGenericsExceptCopyable
13+
func exceptCopyableShorthand<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
14+
1115
@_preInverseGenerics(except: ~Escapable)
1216
func exceptEscapable<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
1317

test/attr/attr_preInverseGenerics.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ func exceptCopyable<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
1313
// expected-error@-1 {{'except' argument to '@_preInverseGenerics' must consist only of inverse constraints such as '~Copyable' or '~Escapable'}}
1414
func exceptInt<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
1515

16+
// The shorthand alias also requires the experimental feature.
17+
@_preInverseGenericsExceptCopyable // expected-error {{'@_preInverseGenerics' is an experimental feature; use '-enable-experimental-feature PreInverseGenericsExcept'}}
18+
func exceptCopyableShorthand<T: ~Copyable & ~Escapable>(_ t: borrowing T) {}
19+
1620

0 commit comments

Comments
 (0)