Skip to content

Commit 863ad15

Browse files
committed
Sema: New syntax for @opened archetypes in textual SIL
The old syntax was @opened("UUID") constraintType Where constraintType was the right hand side of a conformance requirement. This would always create an archetype where the interface type was `Self`, so it couldn't cope with member types of opened existential types. Member types of opened existential types is now a thing with SE-0309, so this lack of support prevented writing SIL test cases using this feature. The new syntax is @opened("UUID", constraintType) interfaceType The interfaceType is a type parameter rooted in an implicit `Self` generic parameter, which is understood to be the underlying type of the existential. Fixes rdar://problem/93771238.
1 parent 43f1466 commit 863ad15

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+735
-638
lines changed

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,10 @@ class ASTContext final {
13251325
bool isRecursivelyConstructingRequirementMachine(
13261326
const ProtocolDecl *proto);
13271327

1328+
/// Retrieve a generic parameter list with a single parameter named `Self`.
1329+
/// This is for parsing @opened archetypes in textual SIL.
1330+
GenericParamList *getSelfGenericParamList(DeclContext *dc) const;
1331+
13281332
/// Retrieve a generic signature with a single unconstrained type parameter,
13291333
/// like `<T>`.
13301334
CanGenericSignature getSingleGenericParameterSignature() const;

include/swift/AST/Attr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2493,6 +2493,9 @@ class TypeAttributes {
24932493
// For an opened existential type, the known ID.
24942494
Optional<UUID> OpenedID;
24952495

2496+
// For an opened existential type, the constraint type.
2497+
Optional<TypeRepr *> ConstraintType;
2498+
24962499
// For a reference to an opaque return type, the mangled name and argument
24972500
// index into the generic signature.
24982501
struct OpaqueReturnTypeRef {
@@ -2581,6 +2584,9 @@ class TypeAttributes {
25812584
bool hasOpenedID() const { return OpenedID.hasValue(); }
25822585
UUID getOpenedID() const { return *OpenedID; }
25832586

2587+
bool hasConstraintType() const { return ConstraintType.hasValue(); }
2588+
TypeRepr *getConstraintType() const { return *ConstraintType; }
2589+
25842590
/// Given a name like "autoclosure", return the type attribute ID that
25852591
/// corresponds to it. This returns TAK_Count on failure.
25862592
///

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5089,8 +5089,10 @@ ERROR(differentiable_function_type_no_differentiability_parameters,
50895089
(/*isLinear*/ bool))
50905090

50915091
// SIL
5092-
ERROR(opened_non_protocol,none,
5093-
"@opened cannot be applied to non-protocol type %0", (Type))
5092+
ERROR(opened_bad_constraint_type,none,
5093+
"@opened constraint type %0 is not a protocol or protocol composition", (Type))
5094+
ERROR(opened_bad_interface_type,none,
5095+
"@opened interface type %0 is not a type parameter", (Type))
50945096
ERROR(sil_function_ellipsis,PointsToFirstBadToken,
50955097
"SIL function types cannot be variadic", ())
50965098
ERROR(sil_function_input_label,PointsToFirstBadToken,

lib/AST/ASTContext.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ struct ASTContext::Implementation {
331331
/// Stores information about lazy deserialization of various declarations.
332332
llvm::DenseMap<const DeclContext *, LazyContextData *> LazyContexts;
333333

334+
/// A fake generic parameter list <Self> for parsing @opened archetypes
335+
/// in textual SIL.
336+
GenericParamList *SelfGenericParamList = nullptr;
337+
334338
/// The single-parameter generic signature with no constraints, <T>.
335339
CanGenericSignature SingleGenericParameterSignature;
336340

@@ -5152,6 +5156,26 @@ ASTContext::getClangTypeForIRGen(Type ty) {
51525156
return getClangTypeConverter().convert(ty).getTypePtrOrNull();
51535157
}
51545158

5159+
GenericParamList *ASTContext::getSelfGenericParamList(DeclContext *dc) const {
5160+
auto *theParamList = getImpl().SelfGenericParamList;
5161+
if (theParamList)
5162+
return theParamList;
5163+
5164+
// Note: we always return a GenericParamList rooted at the first
5165+
// DeclContext this was called with. Since this is just a giant
5166+
// hack for SIL mode, that should be OK.
5167+
auto *selfParam = GenericTypeParamDecl::create(
5168+
dc, Id_Self, SourceLoc(),
5169+
/*isTypeSequence=*/false, /*depth=*/0, /*index=*/0,
5170+
/*isOpaqueType=*/false, /*opaqueTypeRepr=*/nullptr);
5171+
5172+
theParamList = GenericParamList::create(
5173+
const_cast<ASTContext &>(*this), SourceLoc(), {selfParam}, SourceLoc());
5174+
getImpl().SelfGenericParamList = theParamList;
5175+
5176+
return theParamList;
5177+
}
5178+
51555179
CanGenericSignature ASTContext::getSingleGenericParameterSignature() const {
51565180
if (auto theSig = getImpl().SingleGenericParameterSignature)
51575181
return theSig;

lib/AST/ASTPrinter.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/AST/ExistentialLayout.h"
2727
#include "swift/AST/Expr.h"
2828
#include "swift/AST/FileUnit.h"
29+
#include "swift/AST/GenericEnvironment.h"
2930
#include "swift/AST/GenericParamList.h"
3031
#include "swift/AST/GenericSignature.h"
3132
#include "swift/AST/Module.h"
@@ -6307,14 +6308,25 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
63076308
}
63086309

63096310
void visitOpenedArchetypeType(OpenedArchetypeType *T) {
6310-
if (auto parent = T->getParent()) {
6311-
printArchetypeCommon(T);
6312-
return;
6313-
}
6311+
if (Options.PrintForSIL) {
6312+
Printer << "@opened(\"" << T->getOpenedExistentialID() << "\", ";
6313+
visit(T->getGenericEnvironment()->getOpenedExistentialType());
6314+
Printer << ") ";
6315+
6316+
llvm::DenseMap<CanType, Identifier> newAlternativeTypeNames;
63146317

6315-
if (Options.PrintForSIL)
6316-
Printer << "@opened(\"" << T->getOpenedExistentialID() << "\") ";
6317-
visit(T->getExistentialType());
6318+
auto interfaceTy = T->getInterfaceType();
6319+
auto selfTy = interfaceTy->getRootGenericParam();
6320+
auto &ctx = selfTy->getASTContext();
6321+
newAlternativeTypeNames[selfTy->getCanonicalType()] = ctx.Id_Self;
6322+
6323+
PrintOptions subOptions = Options;
6324+
subOptions.AlternativeTypeNames = &newAlternativeTypeNames;
6325+
TypePrinter sub(Printer, subOptions);
6326+
sub.visit(interfaceTy);
6327+
} else {
6328+
visit(T->getExistentialType());
6329+
}
63186330
}
63196331

63206332
void printDependentMember(DependentMemberType *T) {

lib/Parse/ParseDecl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3715,6 +3715,17 @@ ParserStatus Parser::parseTypeAttribute(TypeAttributes &Attributes,
37153715
} else {
37163716
diagnose(Tok, diag::opened_attribute_id_value);
37173717
}
3718+
3719+
if (Tok.is(tok::comma)) {
3720+
consumeToken(tok::comma);
3721+
3722+
auto constraintType = parseType(diag::expected_type);
3723+
if (constraintType.isNonNull())
3724+
Attributes.ConstraintType = constraintType.getPtrOrNull();
3725+
} else {
3726+
diagnose(Tok, diag::attr_expected_comma, "@opened", false);
3727+
}
3728+
37183729
parseMatchingToken(tok::r_paren, endLoc,
37193730
diag::opened_attribute_expected_rparen,
37203731
beginLoc);

lib/Sema/TypeCheckType.cpp

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,27 +2311,65 @@ TypeResolver::resolveAttributedType(AttributedTypeRepr *repr,
23112311
return resolveAttributedType(attrs, repr->getTypeRepr(), options);
23122312
}
23132313

2314-
/// In SIL, handle @opened (n), which creates an existential archetype.
2314+
/// In SIL, handle '@opened(UUID, constraintType) interfaceType',
2315+
/// which creates an opened archetype.
23152316
NeverNullType
23162317
TypeResolver::resolveOpenedExistentialArchetype(
23172318
TypeAttributes &attrs, TypeRepr *repr,
23182319
TypeResolutionOptions options) {
23192320
options.setContext(None);
2320-
Type ty = resolveType(repr, options);
23212321

2322-
if (!ty->isExistentialType()) {
2323-
diagnoseInvalid(repr, attrs.getLoc(TAK_opened), diag::opened_non_protocol,
2324-
ty);
2325-
} else {
2326-
ty = GenericEnvironment::mapTypeIntoContext(
2327-
resolution.getGenericSignature().getGenericEnvironment(), ty);
2328-
ty = OpenedArchetypeType::get(ty->getCanonicalType(),
2329-
GenericSignature(),
2330-
attrs.OpenedID);
2322+
auto *dc = getDeclContext();
2323+
auto &ctx = dc->getASTContext();
2324+
2325+
// The interface type is the type wrapped by the attribute. Resolve it
2326+
// with the fake <Self> generic parameter list uniquely stored in the
2327+
// ASTContext, and use structural resolution to avoid querying the
2328+
// DeclContext's generic signature, which is not the right signature
2329+
// for this.
2330+
auto structuralResolution = TypeResolution::forStructural(
2331+
dc, options,
2332+
/*unboundTyOpener*/ nullptr,
2333+
/*placeholderHandler*/ nullptr);
2334+
TypeResolver interfaceTypeResolver(structuralResolution,
2335+
ctx.getSelfGenericParamList(dc));
2336+
auto interfaceType = interfaceTypeResolver.resolveType(repr, options);
2337+
2338+
// The constraint type is stored inside the attribute. It is resolved
2339+
// normally, as if it were written in the current context.
2340+
auto constraintType = resolveType(attrs.getConstraintType(), options);
2341+
2342+
Type archetypeType;
2343+
if (!constraintType->isExistentialType()) {
2344+
diagnoseInvalid(repr, attrs.getLoc(TAK_opened),
2345+
diag::opened_bad_constraint_type,
2346+
constraintType);
2347+
2348+
archetypeType = ErrorType::get(constraintType->getASTContext());
2349+
} else if (!interfaceType->isTypeParameter()) {
2350+
diagnoseInvalid(repr, attrs.getLoc(TAK_opened),
2351+
diag::opened_bad_interface_type,
2352+
interfaceType);
2353+
2354+
archetypeType = ErrorType::get(interfaceType->getASTContext());
2355+
} {
2356+
// The constraint type is written with respect to the surrounding
2357+
// generic environment.
2358+
constraintType = GenericEnvironment::mapTypeIntoContext(
2359+
resolution.getGenericSignature().getGenericEnvironment(),
2360+
constraintType);
2361+
2362+
// The opened existential type is formed by mapping the interface type
2363+
// into a new opened generic environment.
2364+
archetypeType = OpenedArchetypeType::get(constraintType->getCanonicalType(),
2365+
interfaceType,
2366+
GenericSignature(),
2367+
attrs.getOpenedID());
23312368
}
2369+
23322370
attrs.clearAttribute(TAK_opened);
23332371

2334-
return ty;
2372+
return archetypeType;
23352373
}
23362374

23372375
NeverNullType

test/SILGen/SILDeclRef.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class Derived2: Base {
4040

4141
// CHECK-LABEL: sil @$s10SILDeclRef5testP1ps5Int32VAA1P_p_tF
4242
// Check that witness_method contains SILDeclRefs with a signature.
43-
// CHECK: witness_method $@opened({{.*}}) P, #P.foo : <Self where Self : P> (Self) -> () -> Int32, %{{.*}} : $*@opened({{.*}}) P : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int32
43+
// CHECK: witness_method $@opened({{.*}}, P) Self, #P.foo : <Self where Self : P> (Self) -> () -> Int32, %{{.*}} : $*@opened({{.*}}, P) Self : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int32
4444
public func testP(p: P) -> Int32 {
4545
return p.foo()
4646
}

test/SILGen/address_only_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ func address_only_materialize() -> Int {
142142
// CHECK: [[TEMP:%[0-9]+]] = alloc_stack $Unloadable
143143
// CHECK: [[FUNC:%[0-9]+]] = function_ref @$s18address_only_types05some_a1_B11_function_1{{[_0-9a-zA-Z]*}}F
144144
// CHECK: apply [[FUNC]]([[TEMP]])
145-
// CHECK: [[TEMP_PROJ:%[0-9]+]] = open_existential_addr immutable_access [[TEMP]] : $*Unloadable to $*[[OPENED:@opened(.*) Unloadable]]
145+
// CHECK: [[TEMP_PROJ:%[0-9]+]] = open_existential_addr immutable_access [[TEMP]] : $*Unloadable to $*[[OPENED:@opened\(.*, Unloadable\) Self]]
146146
// CHECK: [[FOO_METHOD:%[0-9]+]] = witness_method $[[OPENED]], #Unloadable.foo :
147147
// CHECK: [[RET:%[0-9]+]] = apply [[FOO_METHOD]]<[[OPENED]]>([[TEMP_PROJ]])
148148
// CHECK: destroy_addr [[TEMP]]

test/SILGen/boxed_existentials.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func test_composition_erasure(_ x: HairType & Error) -> Error {
3434
return x
3535
}
3636
// CHECK-LABEL: sil hidden [ossa] @$s18boxed_existentials24test_composition_erasureys5Error_psAC_AA8HairTypepF
37-
// CHECK: [[VALUE_ADDR:%.*]] = open_existential_addr immutable_access [[OLD_EXISTENTIAL:%.*]] : $*Error & HairType to $*[[VALUE_TYPE:@opened\(.*\) Error & HairType]]
37+
// CHECK: [[VALUE_ADDR:%.*]] = open_existential_addr immutable_access [[OLD_EXISTENTIAL:%.*]] : $*Error & HairType to $*[[VALUE_TYPE:@opened\(.*, Error & HairType\) Self]]
3838
// CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
3939
// CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
4040
// CHECK: store [[NEW_EXISTENTIAL]] to [init] [[NEW_EXISTENTIALBUF:%.*]] :
@@ -49,7 +49,7 @@ func test_class_composition_erasure(_ x: HairClass & Error) -> Error {
4949
return x
5050
}
5151
// CHECK-LABEL: sil hidden [ossa] @$s18boxed_existentials30test_class_composition_erasureys5Error_psAC_AA9HairClasspF
52-
// CHECK: [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $Error & HairClass to $[[VALUE_TYPE:@opened\(.*\) Error & HairClass]]
52+
// CHECK: [[VALUE:%.*]] = open_existential_ref [[OLD_EXISTENTIAL:%.*]] : $Error & HairClass to $[[VALUE_TYPE:@opened\(.*, Error & HairClass\) Self]]
5353
// CHECK: [[NEW_EXISTENTIAL:%.*]] = alloc_existential_box $Error, $[[VALUE_TYPE]]
5454
// CHECK: [[ADDR:%.*]] = project_existential_box $[[VALUE_TYPE]] in [[NEW_EXISTENTIAL]] : $Error
5555
// CHECK: store [[NEW_EXISTENTIAL]] to [init] [[NEW_EXISTENTIALBUF:%.*]] :
@@ -63,7 +63,7 @@ func test_property(_ x: Error) -> String {
6363
}
6464
// CHECK-LABEL: sil hidden [ossa] @$s18boxed_existentials13test_propertyySSs5Error_pF
6565
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Error):
66-
// CHECK: [[VALUE:%.*]] = open_existential_box [[ARG]] : $Error to $*[[VALUE_TYPE:@opened\(.*\) Error]]
66+
// CHECK: [[VALUE:%.*]] = open_existential_box [[ARG]] : $Error to $*[[VALUE_TYPE:@opened\(.*, Error\) Self]]
6767
// FIXME: Extraneous copy here
6868
// CHECK-NEXT: [[COPY:%[0-9]+]] = alloc_stack $[[VALUE_TYPE]]
6969
// CHECK-NEXT: copy_addr [[VALUE]] to [initialization] [[COPY]] : $*[[VALUE_TYPE]]
@@ -89,7 +89,7 @@ func test_property_of_lvalue(_ x: Error) -> String {
8989
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PVAR]] : $*Error
9090
// CHECK: [[VALUE_BOX:%.*]] = load [copy] [[ACCESS]]
9191
// CHECK: [[BORROWED_VALUE_BOX:%.*]] = begin_borrow [[VALUE_BOX]]
92-
// CHECK: [[VALUE:%.*]] = open_existential_box [[BORROWED_VALUE_BOX]] : $Error to $*[[VALUE_TYPE:@opened\(.*\) Error]]
92+
// CHECK: [[VALUE:%.*]] = open_existential_box [[BORROWED_VALUE_BOX]] : $Error to $*[[VALUE_TYPE:@opened\(.*, Error\) Self]]
9393
// CHECK: [[COPY:%.*]] = alloc_stack $[[VALUE_TYPE]]
9494
// CHECK: copy_addr [[VALUE]] to [initialization] [[COPY]]
9595
// CHECK: destroy_value [[VALUE_BOX]]

test/SILGen/builtins.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ func class_archetype_to_native_object<T : C>(_ t: T) -> Builtin.NativeObject {
221221
// CHECK-NEXT: debug_value
222222
// CHECK-NEXT: [[ARG_COPY:%.*]] = copy_value [[ARG]]
223223
// CHECK-NEXT: [[REF:%[0-9]+]] = open_existential_ref [[ARG_COPY]] : $ClassProto
224-
// CHECK-NEXT: [[PTR:%[0-9]+]] = unchecked_ref_cast [[REF]] : $@opened({{.*}}) ClassProto to $Builtin.NativeObject
224+
// CHECK-NEXT: [[PTR:%[0-9]+]] = unchecked_ref_cast [[REF]] : $@opened({{.*}}, ClassProto) Self to $Builtin.NativeObject
225225
// CHECK-NEXT: return [[PTR]]
226226
func class_existential_to_native_object(_ t:ClassProto) -> Builtin.NativeObject {
227227
return Builtin.unsafeCastToNativeObject(t as ClassProto)

test/SILGen/call_as_function.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ func test_call_as_function<T : C>(_ s: S, _ p1: P1, _ p2: P2, _ t: T) {
2323
let _: Int = s(0)
2424

2525
// SR-12590: SILGen crash on existential callAsFunction.
26-
// CHECK: witness_method $@opened({{.+}}) P1, #P1.callAsFunction : <Self where Self : P1> (Self) -> () -> ()
26+
// CHECK: witness_method $@opened({{.+}}, P1) Self, #P1.callAsFunction : <Self where Self : P1> (Self) -> () -> ()
2727
p1()
2828

29-
// CHECK: witness_method $@opened({{.+}}) P2, #P2.callAsFunction : <Self where Self : P2> (Self) -> () -> Self
29+
// CHECK: witness_method $@opened({{.+}}, P2) Self, #P2.callAsFunction : <Self where Self : P2> (Self) -> () -> Self
3030
_ = p2()
3131

3232
// CHECK: class_method %{{.+}} : $C, #C.callAsFunction : (C) -> (String) -> @dynamic_self C, $@convention(method) (@guaranteed String, @guaranteed C) -> @owned C

0 commit comments

Comments
 (0)