Skip to content

Commit c39d6fd

Browse files
committed
[Property Wrappers] Invert the dependency between PropertyWrapperBackingPropertyTypeRequest
and PropertyWrapperAuxiliaryVariablesRequest. Because closure parameter types are inferred in the constraint system, auxiliary variables must be synthesized before the property wrapper type is resolved for single-expression closures.
1 parent 215936d commit c39d6fd

File tree

4 files changed

+64
-88
lines changed

4 files changed

+64
-88
lines changed

lib/AST/TypeCheckRequests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,8 @@ bool AttachedPropertyWrapperTypeRequest::isCached() const {
485485

486486
bool PropertyWrapperBackingPropertyTypeRequest::isCached() const {
487487
auto var = std::get<0>(getStorage());
488-
return !var->getAttrs().isEmpty();
488+
return !var->getAttrs().isEmpty() &&
489+
!(isa<ParamDecl>(var) && isa<ClosureExpr>(var->getDeclContext()));
489490
}
490491

491492
bool PropertyWrapperAuxiliaryVariablesRequest::isCached() const {

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -545,17 +545,14 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate(
545545
if (var->hasImplicitPropertyWrapper())
546546
return var->getInterfaceType();
547547

548-
Type rawType =
549-
evaluateOrDefault(evaluator,
550-
AttachedPropertyWrapperTypeRequest{var, 0}, Type());
548+
// The constraint system will infer closure parameter types
549+
if (isa<ParamDecl>(var) && isa<ClosureExpr>(var->getDeclContext()))
550+
return var->getPropertyWrapperBackingProperty()->getInterfaceType();
551551

552+
Type rawType = var->getAttachedPropertyWrapperType(0);
552553
if (!rawType || rawType->hasError())
553554
return Type();
554555

555-
// The constraint system will infer closure parameter types
556-
if (isa<ParamDecl>(var) && var->getInterfaceType()->hasError())
557-
return Type();
558-
559556
// If there's an initializer of some sort, checking it will determine the
560557
// property wrapper type.
561558
auto binding = var->getParentPatternBinding();
@@ -581,6 +578,22 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate(
581578
ASTContext &ctx = var->getASTContext();
582579
Type type = ctx.getSideCachedPropertyWrapperBackingPropertyType(var);
583580
assert(type || ctx.Diags.hadAnyError());
581+
582+
if (!type)
583+
return Type();
584+
585+
// Set the interface type of each synthesized declaration.
586+
auto auxiliaryVars = var->getPropertyWrapperAuxiliaryVariables();
587+
auxiliaryVars.backingVar->setInterfaceType(type);
588+
589+
if (auto *projection = auxiliaryVars.projectionVar) {
590+
projection->setInterfaceType(computeProjectedValueType(var, type));
591+
}
592+
593+
if (auto *wrappedValue = auxiliaryVars.localWrappedValueVar) {
594+
wrappedValue->setInterfaceType(computeWrappedValueType(var, type));
595+
}
596+
584597
return type;
585598
}
586599

lib/Sema/TypeCheckStorage.cpp

Lines changed: 39 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,8 +2426,6 @@ static VarDecl *synthesizeLocalWrappedValueVar(VarDecl *var) {
24262426
VarDecl *localVar = new (ctx) VarDecl(/*IsStatic=*/false,
24272427
VarDecl::Introducer::Var,
24282428
var->getLoc(), name, dc);
2429-
if (!var->hasImplicitPropertyWrapper())
2430-
localVar->setInterfaceType(var->getInterfaceType());
24312429
localVar->setImplicit();
24322430
localVar->getAttrs() = var->getAttrs();
24332431
localVar->overwriteAccess(var->getFormalAccess());
@@ -2456,8 +2454,7 @@ static VarDecl *synthesizeLocalWrappedValueVar(VarDecl *var) {
24562454
/// Synthesize a computed property `$foo` for a property with an attached
24572455
/// wrapper that has a `projectedValue` property.
24582456
static VarDecl *synthesizePropertyWrapperProjectionVar(
2459-
ASTContext &ctx, VarDecl *var, Type wrapperType,
2460-
VarDecl *wrapperVar) {
2457+
ASTContext &ctx, VarDecl *var, VarDecl *wrapperVar) {
24612458
// If the original property has a @_projectedValueProperty attribute, use
24622459
// that to find the storage wrapper property.
24632460
if (auto attr = var->getAttrs().getAttribute<ProjectedValuePropertyAttr>()){
@@ -2496,33 +2493,16 @@ static VarDecl *synthesizePropertyWrapperProjectionVar(
24962493
}
24972494
Identifier name = ctx.getIdentifier(nameBuf);
24982495

2499-
// Determine the type of the property.
2500-
Type propertyType;
2501-
if (wrapperType)
2502-
propertyType = computeProjectedValueType(var, wrapperType);
2503-
25042496
// Form the property.
25052497
auto dc = var->getDeclContext();
25062498
VarDecl *property = new (ctx) VarDecl(/*IsStatic=*/var->isStatic(),
25072499
VarDecl::Introducer::Var,
25082500
var->getLoc(),
25092501
name, dc);
2510-
if (propertyType)
2511-
property->setInterfaceType(propertyType);
25122502
property->setImplicit();
25132503
property->setOriginalWrappedProperty(var);
25142504
addMemberToContextIfNeeded(property, dc, var);
25152505

2516-
// Create the pattern binding declaration for the property.
2517-
Pattern *pbdPattern = NamedPattern::createImplicit(ctx, property);
2518-
pbdPattern->setType(propertyType);
2519-
pbdPattern = TypedPattern::createImplicit(ctx, pbdPattern, propertyType);
2520-
auto pbd = PatternBindingDecl::createImplicit(
2521-
ctx, property->getCorrectStaticSpelling(), pbdPattern,
2522-
/*init*/nullptr, dc, SourceLoc());
2523-
addMemberToContextIfNeeded(pbd, dc, var);
2524-
pbd->setStatic(var->isStatic());
2525-
25262506
// Determine the access level for the property.
25272507
property->overwriteAccess(var->getFormalAccess());
25282508

@@ -2759,38 +2739,15 @@ PropertyWrapperAuxiliaryVariablesRequest::evaluate(Evaluator &evaluator,
27592739
VarDecl *projectionVar = nullptr;
27602740
VarDecl *wrappedValueVar = nullptr;
27612741

2742+
// Create the backing storage property.
27622743
if (auto *param = dyn_cast<ParamDecl>(var)) {
27632744
backingVar = ParamDecl::cloneWithoutType(ctx, param);
27642745
backingVar->setName(name);
2765-
Type wrapperType;
2766-
2767-
// If this is a function parameter, compute the backing
2768-
// type now. For closure parameters, let the constraint
2769-
// system infer the backing type.
2770-
if (!var->getInterfaceType()->hasError()) {
2771-
wrapperType = var->getPropertyWrapperBackingPropertyType();
2772-
if (!wrapperType || wrapperType->hasError())
2773-
return PropertyWrapperAuxiliaryVariables();
2774-
2775-
backingVar->setInterfaceType(wrapperType);
2776-
}
2777-
}
2778-
2779-
auto wrapperType = var->getPropertyWrapperBackingPropertyType();
2780-
2781-
// Create the backing storage property and note it in the cache.
2782-
if (!backingVar) {
2783-
if (!wrapperType || wrapperType->hasError())
2784-
return PropertyWrapperAuxiliaryVariables();
2785-
2786-
Type storageInterfaceType = wrapperType;
2787-
Type storageType = dc->mapTypeIntoContext(storageInterfaceType);
2788-
2746+
} else {
27892747
backingVar = new (ctx) VarDecl(/*IsStatic=*/var->isStatic(),
27902748
VarDecl::Introducer::Var,
27912749
var->getLoc(),
27922750
name, dc);
2793-
backingVar->setInterfaceType(storageInterfaceType);
27942751
backingVar->setImplicit();
27952752
backingVar->setOriginalWrappedProperty(var);
27962753

@@ -2799,21 +2756,11 @@ PropertyWrapperAuxiliaryVariablesRequest::evaluate(Evaluator &evaluator,
27992756
backingVar->overwriteSetterAccess(AccessLevel::Private);
28002757

28012758
addMemberToContextIfNeeded(backingVar, dc, var);
2802-
2803-
// Create the pattern binding declaration for the backing property.
2804-
Pattern *pbdPattern = NamedPattern::createImplicit(ctx, backingVar);
2805-
pbdPattern->setType(storageType);
2806-
pbdPattern = TypedPattern::createImplicit(ctx, pbdPattern, storageType);
2807-
PatternBindingDecl *pbd = PatternBindingDecl::createImplicit(
2808-
ctx, var->getCorrectStaticSpelling(), pbdPattern, /*init*/nullptr,
2809-
dc, SourceLoc());
2810-
addMemberToContextIfNeeded(pbd, dc, var);
2811-
pbd->setStatic(var->isStatic());
28122759
}
28132760

28142761
if (wrapperInfo.projectedValueVar || var->getName().hasDollarPrefix()) {
28152762
projectionVar = synthesizePropertyWrapperProjectionVar(
2816-
ctx, var, wrapperType, wrapperInfo.projectedValueVar);
2763+
ctx, var, wrapperInfo.projectedValueVar);
28172764
}
28182765

28192766
if ((wrappedValueVar = synthesizeLocalWrappedValueVar(var))) {
@@ -2844,18 +2791,28 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
28442791
if (!wrapperType || wrapperType->hasError())
28452792
return PropertyWrapperInitializerInfo();
28462793

2847-
Type storageInterfaceType = wrapperType;
2848-
Type storageType = dc->mapTypeIntoContext(storageInterfaceType);
2849-
2794+
Type storageType = dc->mapTypeIntoContext(wrapperType);
28502795
Expr *initializer = nullptr;
28512796
PropertyWrapperValuePlaceholderExpr *wrappedValue = nullptr;
28522797

2798+
auto createPBD = [&](VarDecl *singleVar) -> PatternBindingDecl * {
2799+
Pattern *pattern = NamedPattern::createImplicit(ctx, singleVar);
2800+
pattern->setType(singleVar->getType());
2801+
pattern = TypedPattern::createImplicit(ctx, pattern, singleVar->getType());
2802+
PatternBindingDecl *pbd = PatternBindingDecl::createImplicit(
2803+
ctx, var->getCorrectStaticSpelling(), pattern, /*init*/nullptr,
2804+
dc, SourceLoc());
2805+
addMemberToContextIfNeeded(pbd, dc, var);
2806+
pbd->setStatic(var->isStatic());
2807+
return pbd;
2808+
};
2809+
28532810
// Take the initializer from the original property.
28542811
if (!isa<ParamDecl>(var)) {
28552812
auto parentPBD = var->getParentPatternBinding();
28562813
unsigned patternNumber = parentPBD->getPatternEntryIndexForVarDecl(var);
28572814
auto *backingVar = var->getPropertyWrapperBackingProperty();
2858-
auto *pbd = backingVar->getParentPatternBinding();
2815+
auto *pbd = createPBD(backingVar);
28592816

28602817
// Force the default initializer to come into existence, if there is one,
28612818
// and the wrapper doesn't provide its own.
@@ -2897,21 +2854,25 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
28972854
// If there is a projection property (projectedValue) in the wrapper,
28982855
// synthesize a computed property for '$foo'.
28992856
Expr *projectedValueInit = nullptr;
2900-
if (wrapperInfo.projectedValueVar && wrapperInfo.hasProjectedValueInit &&
2901-
isa<ParamDecl>(var)) {
2902-
// Projected-value initialization is currently only supported for parameters.
2903-
auto *param = dyn_cast<ParamDecl>(var);
2904-
auto projectionType = computeProjectedValueType(var, storageType);
2905-
auto *placeholder = PropertyWrapperValuePlaceholderExpr::create(
2906-
ctx, var->getSourceRange(), projectionType, /*projectedValue=*/nullptr);
2907-
projectedValueInit = buildPropertyWrapperInitCall(
2908-
var, storageType, placeholder, PropertyWrapperInitKind::ProjectedValue);
2909-
TypeChecker::typeCheckExpression(projectedValueInit, dc);
2910-
2911-
// Check initializer effects.
2912-
auto *initContext = new (ctx) PropertyWrapperInitializer(
2913-
dc, param, PropertyWrapperInitializer::Kind::ProjectedValue);
2914-
TypeChecker::checkInitializerEffects(initContext, projectedValueInit);
2857+
if (auto *projection = var->getPropertyWrapperProjectionVar()) {
2858+
createPBD(projection);
2859+
2860+
auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo(0);
2861+
if (wrapperInfo.hasProjectedValueInit && isa<ParamDecl>(var)) {
2862+
// Projected-value initialization is currently only supported for parameters.
2863+
auto *param = dyn_cast<ParamDecl>(var);
2864+
auto *placeholder = PropertyWrapperValuePlaceholderExpr::create(
2865+
ctx, var->getSourceRange(), projection->getType(), /*projectedValue=*/nullptr);
2866+
projectedValueInit = buildPropertyWrapperInitCall(
2867+
var, storageType, placeholder, PropertyWrapperInitKind::ProjectedValue);
2868+
TypeChecker::typeCheckExpression(projectedValueInit, dc);
2869+
2870+
// Check initializer effects.
2871+
auto *initContext = new (ctx) PropertyWrapperInitializer(
2872+
dc, param, PropertyWrapperInitializer::Kind::ProjectedValue);
2873+
checkInitializerActorIsolation(initContext, projectedValueInit);
2874+
TypeChecker::checkInitializerEffects(initContext, projectedValueInit);
2875+
}
29152876
}
29162877

29172878
// Form the initialization of the backing property from a value of the
@@ -2920,7 +2881,8 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
29202881
if (wrappedValue) {
29212882
wrappedValueInit = initializer;
29222883
} else if (!initializer &&
2923-
var->allAttachedPropertyWrappersHaveWrappedValueInit()) {
2884+
var->allAttachedPropertyWrappersHaveWrappedValueInit() &&
2885+
!var->getName().hasDollarPrefix()) {
29242886
wrappedValueInit = PropertyWrapperValuePlaceholderExpr::create(
29252887
ctx, var->getSourceRange(), var->getType(), /*wrappedValue=*/nullptr);
29262888

test/SILGen/property_wrapper_parameter.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func genericWrapperCaller(projection: Projection<Int>) {
7272

7373
// CHECK-LABEL: sil hidden [ossa] @$s26property_wrapper_parameter33testSimpleClosureWrapperParameteryyF : $@convention(thin) () -> ()
7474
func testSimpleClosureWrapperParameter() {
75-
let closure: (Int) -> Void = { (@Wrapper value: Int) in
75+
let closure: (Int) -> Void = { (@Wrapper value) in
7676
_ = value
7777
_ = _value
7878
_ = $value
@@ -161,7 +161,7 @@ struct ProjectionWrapper<Value> {
161161

162162
// CHECK-LABEL: sil hidden [ossa] @$s26property_wrapper_parameter27testImplicitPropertyWrapper10projectionyAA010ProjectionG0VySiG_tF : $@convention(thin) (ProjectionWrapper<Int>) -> ()
163163
func testImplicitPropertyWrapper(projection: ProjectionWrapper<Int>) {
164-
let multiStatement: (ProjectionWrapper<Int>) -> Void = { ($value: ProjectionWrapper<Int>) in
164+
let multiStatement: (ProjectionWrapper<Int>) -> Void = { $value in
165165
_ = value
166166
_ = _value
167167
_ = $value
@@ -184,7 +184,7 @@ func testImplicitPropertyWrapper(projection: ProjectionWrapper<Int>) {
184184
// getter of value #1 in closure #1 in implicit closure #1 in testImplicitPropertyWrapper(projection:)
185185
// CHECK: sil private [ossa] @$s26property_wrapper_parameter27testImplicitPropertyWrapper10projectionyAA010ProjectionG0VySiG_tFyAFcfu_yAFcfU_5valueL_Sivg : $@convention(thin) () -> Int
186186

187-
let _: (ProjectionWrapper<Int>) -> (Int, ProjectionWrapper<Int>) = { ($value: ProjectionWrapper<Int>) in
187+
let _: (ProjectionWrapper<Int>) -> (Int, ProjectionWrapper<Int>) = { $value in
188188
(value, $value)
189189
}
190190

0 commit comments

Comments
 (0)