Skip to content

Commit 9cdecf4

Browse files
committed
[Property Wrappers] Compute generic wrapped-value and projected-value
initialization expressions for parameters with attached property wrappers.
1 parent b821c8d commit 9cdecf4

File tree

4 files changed

+123
-76
lines changed

4 files changed

+123
-76
lines changed

include/swift/AST/PropertyWrappers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ struct PropertyWrapperTypeInfo {
6363
HasDefaultValueInit
6464
} defaultInit = NoDefaultValueInit;
6565

66+
bool hasProjectedValueInit = false;
67+
6668
/// The property through which the projection value ($foo) will be accessed.
6769
///
6870
/// This property is optional. If present, a computed property for `$foo`

lib/SILGen/SILGenLValue.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,9 @@ namespace {
13041304

13051305
bool canRewriteSetAsPropertyWrapperInit(SILGenFunction &SGF) const {
13061306
if (auto *VD = dyn_cast<VarDecl>(Storage)) {
1307+
if (VD->isImplicit() || isa<ParamDecl>(VD))
1308+
return false;
1309+
13071310
// If this is not a wrapper property that can be initialized from
13081311
// a value of the wrapped type, we can't perform the initialization.
13091312
auto wrapperInfo = VD->getPropertyWrapperBackingPropertyInfo();

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ PropertyWrapperTypeInfoRequest::evaluate(
339339
result.projectedValueVar =
340340
findValueProperty(ctx, nominal, ctx.Id_projectedValue,
341341
/*allowMissing=*/true);
342+
if (result.projectedValueVar &&
343+
findSuitableWrapperInit(ctx, nominal, result.projectedValueVar,
344+
PropertyWrapperInitKind::ProjectedValue, decls)) {
345+
result.hasProjectedValueInit = true;
346+
}
347+
342348
result.enclosingInstanceWrappedSubscript =
343349
findEnclosingSelfSubscript(ctx, nominal, ctx.Id_wrapped);
344350
result.enclosingInstanceProjectedSubscript =
@@ -527,7 +533,7 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate(
527533
return Type();
528534

529535
// The constraint system will infer closure parameter types
530-
if (isa<ParamDecl>(var) && !var->getDeclContext()->getAsDecl())
536+
if (isa<ParamDecl>(var) && var->getInterfaceType()->hasError())
531537
return Type();
532538

533539
// If there's an initializer of some sort, checking it will determine the

lib/Sema/TypeCheckStorage.cpp

Lines changed: 111 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,117 +2713,139 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
27132713
Identifier name = ctx.getIdentifier(nameBuf);
27142714

27152715
auto dc = var->getDeclContext();
2716+
VarDecl *backingVar = nullptr;
2717+
VarDecl *projectionVar = nullptr;
2718+
27162719
if (auto *param = dyn_cast<ParamDecl>(var)) {
2717-
auto *backingVar = ParamDecl::cloneWithoutType(ctx, param);
2720+
backingVar = ParamDecl::cloneWithoutType(ctx, param);
27182721
backingVar->setName(name);
27192722
Type wrapperType;
27202723

27212724
// If this is a function parameter, compute the backing
27222725
// type now. For closure parameters, let the constraint
27232726
// system infer the backing type.
2724-
if (dc->getAsDecl()) {
2727+
if (!var->getInterfaceType()->hasError()) {
27252728
wrapperType = var->getPropertyWrapperBackingPropertyType();
27262729
if (!wrapperType || wrapperType->hasError())
27272730
return PropertyWrapperBackingPropertyInfo();
27282731

27292732
backingVar->setInterfaceType(wrapperType);
27302733
}
27312734

2732-
VarDecl *projectionVar = nullptr;
27332735
if (wrapperInfo.projectedValueVar || var->getName().hasDollarPrefix()) {
27342736
projectionVar =
27352737
synthesizePropertyWrapperProjectionVar(ctx, var, wrapperType,
27362738
wrapperInfo.projectedValueVar);
27372739
}
2738-
2739-
return PropertyWrapperBackingPropertyInfo(backingVar, projectionVar);
27402740
}
27412741

27422742
if (!wrapperInfo)
2743-
return PropertyWrapperBackingPropertyInfo();
2743+
return PropertyWrapperBackingPropertyInfo(backingVar, projectionVar);
27442744

27452745
// Determine the type of the storage.
27462746
auto wrapperType = var->getPropertyWrapperBackingPropertyType();
27472747
if (!wrapperType || wrapperType->hasError())
2748-
return PropertyWrapperBackingPropertyInfo();
2748+
return PropertyWrapperBackingPropertyInfo(backingVar, projectionVar);
2749+
27492750
Type storageInterfaceType = wrapperType;
27502751
Type storageType = dc->mapTypeIntoContext(storageInterfaceType);
27512752

27522753
// Create the backing storage property and note it in the cache.
2753-
VarDecl *backingVar = new (ctx) VarDecl(/*IsStatic=*/var->isStatic(),
2754-
VarDecl::Introducer::Var,
2755-
var->getLoc(),
2756-
name, dc);
2757-
backingVar->setInterfaceType(storageInterfaceType);
2758-
backingVar->setImplicit();
2759-
backingVar->setOriginalWrappedProperty(var);
2760-
2761-
// The backing storage is 'private'.
2762-
backingVar->overwriteAccess(AccessLevel::Private);
2763-
backingVar->overwriteSetterAccess(AccessLevel::Private);
2764-
2765-
addMemberToContextIfNeeded(backingVar, dc, var);
2766-
2767-
// Create the pattern binding declaration for the backing property.
2768-
Pattern *pbdPattern = NamedPattern::createImplicit(ctx, backingVar);
2769-
pbdPattern->setType(storageType);
2770-
pbdPattern = TypedPattern::createImplicit(ctx, pbdPattern, storageType);
2771-
auto pbd = PatternBindingDecl::createImplicit(
2772-
ctx, var->getCorrectStaticSpelling(), pbdPattern,
2773-
/*init*/ nullptr, dc, SourceLoc());
2774-
addMemberToContextIfNeeded(pbd, dc, var);
2775-
pbd->setStatic(var->isStatic());
2776-
2777-
// Take the initializer from the original property.
2778-
auto parentPBD = var->getParentPatternBinding();
2779-
unsigned patternNumber = parentPBD->getPatternEntryIndexForVarDecl(var);
2780-
2781-
// Force the default initializer to come into existence, if there is one,
2782-
// and the wrapper doesn't provide its own.
2783-
if (!parentPBD->isInitialized(patternNumber)
2784-
&& parentPBD->isDefaultInitializable(patternNumber)
2785-
&& !wrapperInfo.defaultInit) {
2786-
auto ty = parentPBD->getPattern(patternNumber)->getType();
2787-
if (auto defaultInit = TypeChecker::buildDefaultInitializer(ty))
2788-
parentPBD->setInit(patternNumber, defaultInit);
2789-
}
2790-
2791-
if (parentPBD->isInitialized(patternNumber) &&
2792-
!parentPBD->isInitializerChecked(patternNumber)) {
2793-
TypeChecker::typeCheckPatternBinding(parentPBD, patternNumber);
2754+
PatternBindingDecl *pbd = nullptr;
2755+
if (!backingVar) {
2756+
backingVar = new (ctx) VarDecl(/*IsStatic=*/var->isStatic(),
2757+
VarDecl::Introducer::Var,
2758+
var->getLoc(),
2759+
name, dc);
2760+
backingVar->setInterfaceType(storageInterfaceType);
2761+
backingVar->setImplicit();
2762+
backingVar->setOriginalWrappedProperty(var);
2763+
2764+
// The backing storage is 'private'.
2765+
backingVar->overwriteAccess(AccessLevel::Private);
2766+
backingVar->overwriteSetterAccess(AccessLevel::Private);
2767+
2768+
addMemberToContextIfNeeded(backingVar, dc, var);
2769+
2770+
// Create the pattern binding declaration for the backing property.
2771+
Pattern *pbdPattern = NamedPattern::createImplicit(ctx, backingVar);
2772+
pbdPattern->setType(storageType);
2773+
pbdPattern = TypedPattern::createImplicit(ctx, pbdPattern, storageType);
2774+
pbd = PatternBindingDecl::createImplicit(ctx, var->getCorrectStaticSpelling(), pbdPattern,
2775+
/*init*/ nullptr, dc, SourceLoc());
2776+
addMemberToContextIfNeeded(pbd, dc, var);
2777+
pbd->setStatic(var->isStatic());
27942778
}
27952779

27962780
Expr *initializer = nullptr;
27972781
PropertyWrapperValuePlaceholderExpr *wrappedValue = nullptr;
27982782

2799-
if ((initializer = parentPBD->getInit(patternNumber))) {
2800-
pbd->setInit(0, initializer);
2801-
pbd->setInitializerChecked(0);
2802-
wrappedValue = findWrappedValuePlaceholder(initializer);
2803-
} else {
2804-
if (!parentPBD->isInitialized(patternNumber) && wrapperInfo.defaultInit) {
2805-
// FIXME: Record this expression somewhere so that DI can perform the
2806-
// initialization itself.
2807-
Expr *initializer = nullptr;
2808-
typeCheckSynthesizedWrapperInitializer(pbd, backingVar, parentPBD,
2809-
initializer);
2783+
// Take the initializer from the original property.
2784+
if (!isa<ParamDecl>(var)) {
2785+
auto parentPBD = var->getParentPatternBinding();
2786+
unsigned patternNumber = parentPBD->getPatternEntryIndexForVarDecl(var);
2787+
2788+
// Force the default initializer to come into existence, if there is one,
2789+
// and the wrapper doesn't provide its own.
2790+
if (!parentPBD->isInitialized(patternNumber)
2791+
&& parentPBD->isDefaultInitializable(patternNumber)
2792+
&& !wrapperInfo.defaultInit) {
2793+
auto ty = parentPBD->getPattern(patternNumber)->getType();
2794+
if (auto defaultInit = TypeChecker::buildDefaultInitializer(ty))
2795+
parentPBD->setInit(patternNumber, defaultInit);
2796+
}
2797+
2798+
if (parentPBD->isInitialized(patternNumber) &&
2799+
!parentPBD->isInitializerChecked(patternNumber)) {
2800+
TypeChecker::typeCheckPatternBinding(parentPBD, patternNumber);
2801+
}
2802+
2803+
if ((initializer = parentPBD->getInit(patternNumber))) {
28102804
pbd->setInit(0, initializer);
28112805
pbd->setInitializerChecked(0);
2812-
} else if (var->hasObservers() && !dc->isTypeContext()) {
2813-
var->diagnose(diag::observingprop_requires_initializer);
2814-
}
2806+
wrappedValue = findWrappedValuePlaceholder(initializer);
2807+
} else {
2808+
if (!parentPBD->isInitialized(patternNumber) && wrapperInfo.defaultInit) {
2809+
// FIXME: Record this expression somewhere so that DI can perform the
2810+
// initialization itself.
2811+
Expr *initializer = nullptr;
2812+
typeCheckSynthesizedWrapperInitializer(pbd, backingVar, parentPBD,
2813+
initializer);
2814+
pbd->setInit(0, initializer);
2815+
pbd->setInitializerChecked(0);
2816+
} else if (var->hasObservers() && !dc->isTypeContext()) {
2817+
var->diagnose(diag::observingprop_requires_initializer);
2818+
}
28152819

2816-
if (var->getOpaqueResultTypeDecl()) {
2817-
var->diagnose(diag::opaque_type_var_no_underlying_type);
2820+
if (var->getOpaqueResultTypeDecl()) {
2821+
var->diagnose(diag::opaque_type_var_no_underlying_type);
2822+
}
28182823
}
28192824
}
28202825

28212826
// If there is a projection property (projectedValue) in the wrapper,
28222827
// synthesize a computed property for '$foo'.
2823-
VarDecl *storageVar = nullptr;
2828+
Expr *projectedValueInit = nullptr;
28242829
if (wrapperInfo.projectedValueVar) {
2825-
storageVar = synthesizePropertyWrapperProjectionVar(
2826-
ctx, var, storageInterfaceType, wrapperInfo.projectedValueVar);
2830+
if (!projectionVar) {
2831+
projectionVar = synthesizePropertyWrapperProjectionVar(ctx, var, storageInterfaceType,
2832+
wrapperInfo.projectedValueVar);
2833+
}
2834+
2835+
// Projected-value initialization is currently only supported for parameters.
2836+
if (wrapperInfo.hasProjectedValueInit && isa<ParamDecl>(var)) {
2837+
auto *param = dyn_cast<ParamDecl>(var);
2838+
auto *placeholder = PropertyWrapperValuePlaceholderExpr::create(
2839+
ctx, var->getSourceRange(), projectionVar->getType(), /*projectedValue=*/nullptr);
2840+
projectedValueInit = buildPropertyWrapperInitCall(var, backingVar->getType(),
2841+
placeholder, PropertyWrapperInitKind::ProjectedValue);
2842+
TypeChecker::typeCheckExpression(projectedValueInit, dc);
2843+
2844+
// Check initializer effects.
2845+
auto *initContext = new (ctx) PropertyWrapperInitializer(
2846+
dc, param, PropertyWrapperInitializer::Kind::ProjectedValue);
2847+
TypeChecker::checkInitializerEffects(initContext, projectedValueInit);
2848+
}
28272849
}
28282850

28292851
// If no initial wrapped value was provided via '=' and either:
@@ -2834,21 +2856,35 @@ PropertyWrapperBackingPropertyInfoRequest::evaluate(Evaluator &evaluator,
28342856
// value.
28352857
if (!wrappedValue && (!var->allAttachedPropertyWrappersHaveWrappedValueInit() ||
28362858
initializer)) {
2837-
return PropertyWrapperBackingPropertyInfo(backingVar, storageVar);
2859+
return PropertyWrapperBackingPropertyInfo(backingVar, projectionVar, nullptr,
2860+
projectedValueInit);
28382861
}
28392862

28402863
// Form the initialization of the backing property from a value of the
28412864
// original property's type.
2842-
if (!initializer) {
2843-
initializer = PropertyWrapperValuePlaceholderExpr::create(
2865+
Expr *wrappedValueInit = initializer;
2866+
if (!wrappedValueInit) {
2867+
wrappedValueInit = PropertyWrapperValuePlaceholderExpr::create(
28442868
ctx, var->getSourceRange(), var->getType(), /*wrappedValue=*/nullptr);
2845-
typeCheckSynthesizedWrapperInitializer(
2846-
pbd, backingVar, parentPBD, initializer);
2869+
2870+
if (auto *param = dyn_cast<ParamDecl>(var)) {
2871+
wrappedValueInit = buildPropertyWrapperInitCall(var, backingVar->getType(), wrappedValueInit,
2872+
PropertyWrapperInitKind::WrappedValue);
2873+
TypeChecker::typeCheckExpression(wrappedValueInit, dc);
2874+
2875+
// Check initializer effects.
2876+
auto *initContext = new (ctx) PropertyWrapperInitializer(
2877+
dc, param, PropertyWrapperInitializer::Kind::WrappedValue);
2878+
TypeChecker::checkInitializerEffects(initContext, wrappedValueInit);
2879+
} else {
2880+
typeCheckSynthesizedWrapperInitializer(
2881+
pbd, backingVar, var->getParentPatternBinding(), wrappedValueInit);
2882+
}
28472883
}
28482884

2849-
return PropertyWrapperBackingPropertyInfo(backingVar, storageVar,
2850-
/*wrappedValueInitExpr=*/initializer,
2851-
/*projectedValueInitExpr=*/nullptr);
2885+
return PropertyWrapperBackingPropertyInfo(backingVar, projectionVar,
2886+
wrappedValueInit,
2887+
projectedValueInit);
28522888
}
28532889

28542890
VarDecl *

0 commit comments

Comments
 (0)