Skip to content

Commit 8f706b8

Browse files
committed
[ConstraintSystem] Always choose an available type eraser type.
If no available type eraser type exists, do not perform type erasure. If multiple type erasers exist, choose the least available type eraser type. Which type eraser to choose is based on the availability of the lexical context of the erased expression.
1 parent 1fcb944 commit 8f706b8

File tree

3 files changed

+90
-7
lines changed

3 files changed

+90
-7
lines changed

include/swift/AST/DeclAttr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ SIMPLE_DECL_ATTR(_inheritsConvenienceInitializers, InheritsConvenienceInitialize
267267
OnClass | UserInaccessible | NotSerialized | APIStableToAdd | ABIStableToAdd | APIBreakingToRemove | ABIBreakingToRemove,
268268
93)
269269
DECL_ATTR(_typeEraser, TypeEraser,
270-
OnProtocol | UserInaccessible | ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove,
270+
OnProtocol | UserInaccessible | ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIBreakingToRemove | AllowMultipleAttributes,
271271
94)
272272
SIMPLE_DECL_ATTR(IBSegueAction, IBSegueAction,
273273
OnFunc | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,

lib/Sema/ConstraintSystem.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4553,6 +4553,8 @@ Expr *ConstraintSystem::buildAutoClosureExpr(Expr *expr,
45534553
Expr *ConstraintSystem::buildTypeErasedExpr(Expr *expr, DeclContext *dc,
45544554
Type contextualType,
45554555
ContextualTypePurpose purpose) {
4556+
auto &ctx = dc->getASTContext();
4557+
45564558
if (purpose != CTP_ReturnStmt)
45574559
return expr;
45584560

@@ -4571,13 +4573,33 @@ Expr *ConstraintSystem::buildTypeErasedExpr(Expr *expr, DeclContext *dc,
45714573
return expr;
45724574

45734575
auto *PD = protocols.front();
4574-
auto *attr = PD->getAttrs().getAttribute<TypeEraserAttr>();
4575-
if (!attr)
4576+
4577+
auto contextAvailability =
4578+
TypeChecker::availabilityAtLocation(expr->getLoc(), dc);
4579+
auto refinedAvailability =
4580+
AvailabilityContext::forPlatformRange(
4581+
AvailabilityRange::alwaysAvailable(), ctx);
4582+
4583+
// The least available type eraser for the enclosing context.
4584+
Type typeEraser;
4585+
for (auto *attr : PD->getAttrs().getAttributes<TypeEraserAttr>()) {
4586+
auto eraser = attr->getResolvedType(PD);
4587+
assert(eraser && "Failed to resolve eraser type!");
4588+
4589+
auto *nominal = eraser->getAnyNominal();
4590+
auto nominalAvailability =
4591+
TypeChecker::availabilityForDeclSignature(nominal);
4592+
4593+
if (contextAvailability.isContainedIn(nominalAvailability) &&
4594+
nominalAvailability.isContainedIn(refinedAvailability)) {
4595+
refinedAvailability = nominalAvailability;
4596+
typeEraser = eraser;
4597+
}
4598+
}
4599+
4600+
if (!typeEraser)
45764601
return expr;
45774602

4578-
auto typeEraser = attr->getResolvedType(PD);
4579-
assert(typeEraser && "Failed to resolve eraser type!");
4580-
auto &ctx = dc->getASTContext();
45814603
auto *argList = ArgumentList::forImplicitSingle(ctx, ctx.Id_erasing, expr);
45824604
return CallExpr::createImplicit(
45834605
ctx, TypeExpr::createImplicit(typeEraser, ctx), argList);

test/Sema/type_eraser.swift

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
// RUN: %target-swift-frontend -typecheck -disable-availability-checking -dump-ast %s | %FileCheck %s
1+
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx10.15 -typecheck -dump-ast %s | %FileCheck %s
2+
3+
// REQUIRES: OS=macosx
24

35
class AnyP: P {
46
init<T: P>(erasing: T) {}
57
}
68

79
@_typeEraser(AnyP)
10+
@_typeEraser(NewAnyP)
811
protocol P {}
912

1013
struct ConcreteP: P, Hashable {}
@@ -119,3 +122,61 @@ extension DynamicReplacement {
119122
return ConcreteP()
120123
}
121124
}
125+
126+
@available(macOS 100, *)
127+
struct NewAnyP: P {
128+
init(erasing: some P) {}
129+
}
130+
131+
@available(macOS 100, *)
132+
struct NewConcreteP: P {}
133+
134+
// CHECK-LABEL: var_decl{{.*}}x0
135+
dynamic var x0: some P {
136+
// CHECK: return_stmt
137+
// CHECK-NEXT: underlying_to_opaque_expr implicit type="some P"
138+
// CHECK-NEXT: call_expr implicit type="AnyP"
139+
ConcreteP()
140+
}
141+
142+
// CHECK-LABEL: var_decl{{.*}}x1
143+
@available(macOS 99, *)
144+
dynamic var x1: some P {
145+
// CHECK: return_stmt
146+
// CHECK-NEXT: underlying_to_opaque_expr implicit type="some P"
147+
// CHECK-NEXT: call_expr implicit type="AnyP"
148+
ConcreteP()
149+
}
150+
151+
// CHECK-LABEL: var_decl{{.*}}x2
152+
@available(macOS 100, *)
153+
dynamic var x2: some P {
154+
// CHECK: return_stmt
155+
// CHECK-NEXT: underlying_to_opaque_expr implicit type="some P"
156+
// CHECK-NEXT: call_expr implicit type="NewAnyP"
157+
ConcreteP()
158+
}
159+
160+
// CHECK-LABEL: var_decl{{.*}}x3
161+
@available(macOS 101, *)
162+
dynamic var x3: some P {
163+
// CHECK: return_stmt
164+
// CHECK-NEXT: underlying_to_opaque_expr implicit type="some P"
165+
// CHECK-NEXT: call_expr implicit type="NewAnyP"
166+
ConcreteP()
167+
}
168+
169+
// CHECK-LABEL: var_decl{{.*}}x4
170+
dynamic var x4: some P {
171+
if #available(macOS 101, *) {
172+
// CHECK: return_stmt
173+
// CHECK-NEXT: underlying_to_opaque_expr implicit type="some P"
174+
// CHECK-NEXT: call_expr implicit type="NewAnyP"
175+
return NewConcreteP()
176+
} else {
177+
// CHECK: return_stmt
178+
// CHECK-NEXT: underlying_to_opaque_expr implicit type="some P"
179+
// CHECK-NEXT: call_expr implicit type="AnyP"
180+
return ConcreteP()
181+
}
182+
}

0 commit comments

Comments
 (0)