Skip to content

Commit 9f71ee1

Browse files
authored
Merge pull request #38766 from hborla/wrapped-argument-conversions
[Property Wrappers] Fix a bug where wrapped arguments were not properly coerced to the wrapper generator input type.
2 parents c3390ec + 39c8eb4 commit 9f71ee1

12 files changed

+142
-58
lines changed

include/swift/AST/Initializer.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,15 +209,16 @@ class PropertyWrapperInitializer : public Initializer {
209209
};
210210

211211
private:
212-
ParamDecl *param;
212+
VarDecl *wrappedVar;
213213
Kind kind;
214214

215215
public:
216-
explicit PropertyWrapperInitializer(DeclContext *parent, ParamDecl *param, Kind kind)
216+
explicit PropertyWrapperInitializer(DeclContext *parent, VarDecl *wrappedVar,
217+
Kind kind)
217218
: Initializer(InitializerKind::PropertyWrapper, parent),
218-
param(param), kind(kind) {}
219+
wrappedVar(wrappedVar), kind(kind) {}
219220

220-
ParamDecl *getParam() const { return param; }
221+
VarDecl *getWrappedVar() const { return wrappedVar; }
221222

222223
Kind getKind() const { return kind; }
223224

include/swift/Sema/ConstraintSystem.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,6 +1706,10 @@ class SolutionApplicationTarget {
17061706
static SolutionApplicationTarget forUninitializedWrappedVar(
17071707
VarDecl *wrappedVar);
17081708

1709+
/// Form a target for a synthesized property wrapper initializer.
1710+
static SolutionApplicationTarget forPropertyWrapperInitializer(
1711+
VarDecl *wrappedVar, DeclContext *dc, Expr *initializer);
1712+
17091713
Expr *getAsExpr() const {
17101714
switch (kind) {
17111715
case Kind::expression:
@@ -1813,7 +1817,7 @@ class SolutionApplicationTarget {
18131817
bool isOptionalSomePatternInit() const {
18141818
return kind == Kind::expression &&
18151819
expression.contextualPurpose == CTP_Initialization &&
1816-
isa<OptionalSomePattern>(expression.pattern) &&
1820+
dyn_cast_or_null<OptionalSomePattern>(expression.pattern) &&
18171821
!expression.pattern->isImplicit();
18181822
}
18191823

@@ -1837,7 +1841,9 @@ class SolutionApplicationTarget {
18371841

18381842
// Don't create property wrapper generator functions for static variables and
18391843
// local variables with initializers.
1840-
if (wrappedVar->isStatic() || wrappedVar->getDeclContext()->isLocalContext())
1844+
bool hasInit = expression.propertyWrapper.hasInitialWrappedValue;
1845+
if (wrappedVar->isStatic() ||
1846+
(hasInit && wrappedVar->getDeclContext()->isLocalContext()))
18411847
return false;
18421848

18431849
return expression.propertyWrapper.innermostWrappedValueInit == apply;

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,10 +2138,10 @@ void ASTMangler::appendContext(const DeclContext *ctx, StringRef useModuleName)
21382138
auto wrapperInit = cast<PropertyWrapperInitializer>(ctx);
21392139
switch (wrapperInit->getKind()) {
21402140
case PropertyWrapperInitializer::Kind::WrappedValue:
2141-
appendBackingInitializerEntity(wrapperInit->getParam());
2141+
appendBackingInitializerEntity(wrapperInit->getWrappedVar());
21422142
break;
21432143
case PropertyWrapperInitializer::Kind::ProjectedValue:
2144-
appendInitFromProjectedValueEntity(wrapperInit->getParam());
2144+
appendInitFromProjectedValueEntity(wrapperInit->getWrappedVar());
21452145
break;
21462146
}
21472147
return;

lib/AST/DeclContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ unsigned DeclContext::printContext(raw_ostream &OS, const unsigned indent,
679679
}
680680
case InitializerKind::PropertyWrapper: {
681681
auto init = cast<PropertyWrapperInitializer>(this);
682-
OS << "PropertyWrapper 0x" << (void*)init->getParam() << ", kind=";
682+
OS << "PropertyWrapper 0x" << (void*)init->getWrappedVar() << ", kind=";
683683
switch (init->getKind()) {
684684
case PropertyWrapperInitializer::Kind::WrappedValue:
685685
OS << "wrappedValue";

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,8 +1296,8 @@ class ExprContextAnalyzer {
12961296
auto AFD = dyn_cast<AbstractFunctionDecl>(initDC->getParent());
12971297
if (!AFD)
12981298
return;
1299-
auto *param = initDC->getParam();
1300-
recordPossibleType(AFD->mapTypeIntoContext(param->getInterfaceType()));
1299+
auto *var = initDC->getWrappedVar();
1300+
recordPossibleType(AFD->mapTypeIntoContext(var->getInterfaceType()));
13011301
break;
13021302
}
13031303
}

lib/Sema/CSApply.cpp

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6030,16 +6030,44 @@ Expr *ExprRewriter::coerceCallArguments(
60306030
};
60316031

60326032
if (paramInfo.hasExternalPropertyWrapper(paramIdx)) {
6033-
auto *param = getParameterAt(callee.getDecl(), paramIdx);
6033+
auto *paramDecl = getParameterAt(callee.getDecl(), paramIdx);
60346034
auto appliedWrapper = appliedPropertyWrappers[appliedWrapperIndex++];
60356035
auto wrapperType = solution.simplifyType(appliedWrapper.wrapperType);
60366036
auto initKind = appliedWrapper.initKind;
60376037

6038-
using ValueKind = AppliedPropertyWrapperExpr::ValueKind;
6039-
ValueKind valueKind = (initKind == PropertyWrapperInitKind::ProjectedValue ?
6040-
ValueKind::ProjectedValue : ValueKind::WrappedValue);
6038+
AppliedPropertyWrapperExpr::ValueKind valueKind;
6039+
PropertyWrapperValuePlaceholderExpr *generatorArg;
6040+
auto initInfo = paramDecl->getPropertyWrapperInitializerInfo();
6041+
if (initKind == PropertyWrapperInitKind::ProjectedValue) {
6042+
valueKind = AppliedPropertyWrapperExpr::ValueKind::ProjectedValue;
6043+
generatorArg = initInfo.getProjectedValuePlaceholder();
6044+
} else {
6045+
valueKind = AppliedPropertyWrapperExpr::ValueKind::WrappedValue;
6046+
generatorArg = initInfo.getWrappedValuePlaceholder();
6047+
}
6048+
6049+
// Coerce the property wrapper argument type to the input type of
6050+
// the property wrapper generator function. The wrapper generator
6051+
// has the same generic signature as the enclosing function, so we
6052+
// can use substitutions from the callee.
6053+
Type generatorInputType =
6054+
generatorArg->getType().subst(callee.getSubstitutions());
6055+
auto argLoc = getArgLocator(argIdx, paramIdx, param.getParameterFlags());
6056+
6057+
if (generatorArg->isAutoClosure()) {
6058+
auto *closureType = generatorInputType->castTo<FunctionType>();
6059+
arg = coerceToType(
6060+
arg, closureType->getResult(),
6061+
argLoc.withPathElement(ConstraintLocator::AutoclosureResult));
6062+
arg = cs.buildAutoClosureExpr(arg, closureType, dc);
6063+
}
60416064

6042-
arg = AppliedPropertyWrapperExpr::create(ctx, callee, param, arg->getStartLoc(),
6065+
arg = coerceToType(arg, generatorInputType, argLoc);
6066+
6067+
// Wrap the argument in an applied property wrapper expr, which will
6068+
// later turn into a call to the property wrapper generator function.
6069+
arg = AppliedPropertyWrapperExpr::create(ctx, callee, paramDecl,
6070+
arg->getStartLoc(),
60436071
wrapperType, arg, valueKind);
60446072
cs.cacheExprTypes(arg);
60456073
}
@@ -8416,13 +8444,18 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
84168444
// been subsumed by the backing property.
84178445
if (wrappedVar) {
84188446
ASTContext &ctx = cs.getASTContext();
8419-
wrappedVar->getParentPatternBinding()->setInitializerSubsumed(0);
84208447
ctx.setSideCachedPropertyWrapperBackingPropertyType(
84218448
wrappedVar, initType->mapTypeOutOfContext());
84228449

84238450
// Record the semantic initializer on the outermost property wrapper.
84248451
wrappedVar->getAttachedPropertyWrappers().front()
84258452
->setSemanticInit(initializer);
8453+
8454+
// If this is a wrapped parameter, we're done.
8455+
if (isa<ParamDecl>(wrappedVar))
8456+
return resultTarget;
8457+
8458+
wrappedVar->getParentPatternBinding()->setInitializerSubsumed(0);
84268459
}
84278460

84288461
// Coerce the pattern to the type of the initializer.

lib/Sema/ConstraintSystem.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5287,7 +5287,14 @@ SolutionApplicationTarget::SolutionApplicationTarget(
52875287
void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
52885288
assert(kind == Kind::expression);
52895289
assert(expression.contextualPurpose == CTP_Initialization);
5290-
auto singleVar = expression.pattern->getSingleVar();
5290+
5291+
VarDecl *singleVar;
5292+
if (auto *pattern = expression.pattern) {
5293+
singleVar = pattern->getSingleVar();
5294+
} else {
5295+
singleVar = expression.propertyWrapper.wrappedVar;
5296+
}
5297+
52915298
if (!singleVar)
52925299
return;
52935300

@@ -5417,6 +5424,23 @@ SolutionApplicationTarget::forUninitializedWrappedVar(VarDecl *wrappedVar) {
54175424
return SolutionApplicationTarget(wrappedVar);
54185425
}
54195426

5427+
SolutionApplicationTarget
5428+
SolutionApplicationTarget::forPropertyWrapperInitializer(
5429+
VarDecl *wrappedVar, DeclContext *dc, Expr *initializer) {
5430+
SolutionApplicationTarget target(
5431+
initializer, dc, CTP_Initialization, wrappedVar->getType(),
5432+
/*isDiscarded=*/false);
5433+
target.expression.propertyWrapper.wrappedVar = wrappedVar;
5434+
if (auto *patternBinding = wrappedVar->getParentPatternBinding()) {
5435+
auto index = patternBinding->getPatternEntryIndexForVarDecl(wrappedVar);
5436+
target.expression.initialization.patternBinding = patternBinding;
5437+
target.expression.initialization.patternBindingIndex = index;
5438+
target.expression.pattern = patternBinding->getPattern(index);
5439+
}
5440+
target.maybeApplyPropertyWrapper();
5441+
return target;
5442+
}
5443+
54205444
ContextualPattern
54215445
SolutionApplicationTarget::getContextualPattern() const {
54225446
assert(kind == Kind::expression);

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ static void forEachOuterDecl(DeclContext *DC, Fn fn) {
114114
case DeclContextKind::Initializer:
115115
if (auto *PBI = dyn_cast<PatternBindingInitializer>(DC))
116116
fn(PBI->getBinding());
117+
else if (auto *I = dyn_cast<PropertyWrapperInitializer>(DC))
118+
fn(I->getWrappedVar());
117119
break;
118120

119121
case DeclContextKind::SubscriptDecl:

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2612,8 +2612,8 @@ void swift::checkEnumElementActorIsolation(
26122612
}
26132613

26142614
void swift::checkPropertyWrapperActorIsolation(
2615-
PatternBindingDecl *binding, Expr *expr) {
2616-
ActorIsolationChecker checker(binding->getDeclContext());
2615+
VarDecl *wrappedVar, Expr *expr) {
2616+
ActorIsolationChecker checker(wrappedVar->getDeclContext());
26172617
expr->walk(checker);
26182618
}
26192619

lib/Sema/TypeCheckConcurrency.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class ProtocolConformance;
4545
class TopLevelCodeDecl;
4646
class TypeBase;
4747
class ValueDecl;
48+
class VarDecl;
4849

4950
/// Add notes suggesting the addition of 'async', as appropriate,
5051
/// to a diagnostic for a function that isn't an async context.
@@ -57,8 +58,7 @@ void checkActorConstructor(ClassDecl *decl, ConstructorDecl *ctor);
5758
void checkActorConstructorBody(ClassDecl *decl, ConstructorDecl *ctor, BraceStmt *body);
5859
void checkInitializerActorIsolation(Initializer *init, Expr *expr);
5960
void checkEnumElementActorIsolation(EnumElementDecl *element, Expr *expr);
60-
void checkPropertyWrapperActorIsolation(
61-
PatternBindingDecl *binding, Expr *expr);
61+
void checkPropertyWrapperActorIsolation(VarDecl *wrappedVar, Expr *expr);
6262

6363
/// Determine the isolation of a particular closure.
6464
///

lib/Sema/TypeCheckStorage.cpp

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,31 +2586,24 @@ static VarDecl *synthesizePropertyWrapperProjectionVar(
25862586

25872587
static void typeCheckSynthesizedWrapperInitializer(VarDecl *wrappedVar,
25882588
Expr *&initializer) {
2589-
// Figure out the context in which the initializer was written.
2590-
auto *parentPBD = wrappedVar->getParentPatternBinding();
2591-
auto i = parentPBD->getPatternEntryIndexForVarDecl(wrappedVar);
2592-
DeclContext *originalDC = parentPBD->getDeclContext();
2593-
if (!originalDC->isLocalContext()) {
2594-
auto initContext =
2595-
cast_or_null<PatternBindingInitializer>(parentPBD->getInitContext(i));
2596-
if (initContext)
2597-
originalDC = initContext;
2598-
}
2589+
auto *dc = wrappedVar->getInnermostDeclContext();
2590+
auto &ctx = wrappedVar->getASTContext();
2591+
auto *initContext = new (ctx) PropertyWrapperInitializer(
2592+
dc, wrappedVar, PropertyWrapperInitializer::Kind::WrappedValue);
25992593

26002594
// Type-check the initialization.
2601-
auto *pattern = parentPBD->getPattern(i);
2602-
TypeChecker::typeCheckBinding(pattern, initializer, originalDC,
2603-
wrappedVar->getType(), parentPBD, i);
2595+
using namespace constraints;
2596+
auto target = SolutionApplicationTarget::forPropertyWrapperInitializer(
2597+
wrappedVar, initContext, initializer);
2598+
auto result = TypeChecker::typeCheckExpression(target);
2599+
if (!result)
2600+
return;
26042601

2605-
if (auto initializerContext =
2606-
dyn_cast_or_null<Initializer>(parentPBD->getInitContext(i))) {
2607-
TypeChecker::contextualizeInitializer(initializerContext, initializer);
2608-
}
2602+
initializer = result->getAsExpr();
26092603

2610-
auto *backingVar = wrappedVar->getPropertyWrapperBackingProperty();
2611-
auto *backingPBD = backingVar->getParentPatternBinding();
2612-
checkPropertyWrapperActorIsolation(backingPBD, initializer);
2613-
TypeChecker::checkPropertyWrapperEffects(backingPBD, initializer);
2604+
TypeChecker::contextualizeInitializer(initContext, initializer);
2605+
checkPropertyWrapperActorIsolation(wrappedVar, initializer);
2606+
TypeChecker::checkInitializerEffects(initContext, initializer);
26142607
}
26152608

26162609
static PropertyWrapperMutability::Value
@@ -2969,21 +2962,7 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
29692962
!var->getName().hasDollarPrefix()) {
29702963
wrappedValueInit = PropertyWrapperValuePlaceholderExpr::create(
29712964
ctx, var->getSourceRange(), var->getType(), /*wrappedValue=*/nullptr);
2972-
2973-
if (auto *param = dyn_cast<ParamDecl>(var)) {
2974-
wrappedValueInit = buildPropertyWrapperInitCall(
2975-
var, storageType, wrappedValueInit, PropertyWrapperInitKind::WrappedValue);
2976-
TypeChecker::typeCheckExpression(wrappedValueInit, dc);
2977-
2978-
// Check initializer effects.
2979-
auto *initContext = new (ctx) PropertyWrapperInitializer(
2980-
dc, param, PropertyWrapperInitializer::Kind::WrappedValue);
2981-
TypeChecker::contextualizeInitializer(initContext, wrappedValueInit);
2982-
checkInitializerActorIsolation(initContext, wrappedValueInit);
2983-
TypeChecker::checkInitializerEffects(initContext, wrappedValueInit);
2984-
} else {
2985-
typeCheckSynthesizedWrapperInitializer(var, wrappedValueInit);
2986-
}
2965+
typeCheckSynthesizedWrapperInitializer(var, wrappedValueInit);
29872966
}
29882967

29892968
return PropertyWrapperInitializerInfo(wrappedValueInit, projectedValueInit);

test/SILGen/property_wrapper_parameter.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func simpleWrapperParameterCaller(projection: Projection<Int>) {
5252

5353
testSimpleWrapperParameter($value: projection)
5454
// CHECK: function_ref @$s26property_wrapper_parameter26testSimpleWrapperParameter5valueyAA0F0VySiG_tFACL_SivpfW : $@convention(thin) (Projection<Int>) -> Wrapper<Int>
55+
56+
var x: Int = 10
57+
testSimpleWrapperParameter(value: x)
58+
// CHECK: function_ref @$s26property_wrapper_parameter26testSimpleWrapperParameter5valueyAA0F0VySiG_tFACL_SivpfP : $@convention(thin) (Int) -> Wrapper<Int>
5559
}
5660

5761
// CHECK-LABEL: sil [ossa] @$s26property_wrapper_parameter18testGenericWrapper5valueyAA0F0VyxG_tlF : $@convention(thin) <T> (@in_guaranteed Wrapper<T>) -> ()
@@ -71,6 +75,41 @@ func genericWrapperCaller(projection: Projection<Int>) {
7175

7276
testGenericWrapper($value: projection)
7377
// CHECK: function_ref @$s26property_wrapper_parameter18testGenericWrapper5valueyAA0F0VyxG_tlFACL_xvpfW : $@convention(thin) <τ_0_0> (@in Projection<τ_0_0>) -> @out Wrapper<τ_0_0>
78+
79+
var x: Int = 10
80+
testGenericWrapper(value: x)
81+
// CHECK: function_ref @$s26property_wrapper_parameter18testGenericWrapper5valueyAA0F0VyxG_tlFACL_xvpfP : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out Wrapper<τ_0_0>
82+
}
83+
84+
@propertyWrapper
85+
public struct AutoClosureWrapper<T> {
86+
public var wrappedValue: T
87+
88+
// CHECK-LABEL: sil [ossa] @$s26property_wrapper_parameter18AutoClosureWrapperV12wrappedValueACyxGxyXK_tcfC : $@convention(method) <T> (@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T>, @thin AutoClosureWrapper<T>.Type) -> @out AutoClosureWrapper<T>
89+
public init(wrappedValue: @autoclosure () -> T) {
90+
self.wrappedValue = wrappedValue()
91+
}
92+
93+
public var projectedValue: Projection<T> {
94+
Projection(wrappedValue: wrappedValue)
95+
}
96+
97+
public init(projectedValue: Projection<T>) {
98+
self.wrappedValue = projectedValue.wrappedValue
99+
}
100+
}
101+
102+
// CHECK-LABEL: sil hidden [ossa] @$s26property_wrapper_parameter22testAutoClosureWrapper5valueyAA0efG0VyxG_tlF : $@convention(thin) <T> (@in_guaranteed AutoClosureWrapper<T>) -> ()
103+
func testAutoClosureWrapper<T>(@AutoClosureWrapper value: T) {
104+
// property wrapper backing initializer of value #1 in testAutoClosureWrapper<A>(value:)
105+
// CHECK-LABEL: sil private [ossa] @$s26property_wrapper_parameter22testAutoClosureWrapper5valueyAA0efG0VyxG_tlFACL_xvpfP : $@convention(thin) <T> (@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T>) -> @out AutoClosureWrapper<T>
106+
// CHECK: function_ref @$s26property_wrapper_parameter18AutoClosureWrapperV12wrappedValueACyxGxyXK_tcfC : $@convention(method) <τ_0_0> (@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>, @thin AutoClosureWrapper<τ_0_0>.Type) -> @out AutoClosureWrapper<τ_0_0>
107+
}
108+
109+
// CHECK-LABEL: sil hidden [ossa] @$s26property_wrapper_parameter24autoClosureWrapperCalleryyF : $@convention(thin) () -> ()
110+
func autoClosureWrapperCaller() {
111+
testAutoClosureWrapper(value: 10)
112+
// CHECK: function_ref @$s26property_wrapper_parameter22testAutoClosureWrapper5valueyAA0efG0VyxG_tlFACL_xvpfP : $@convention(thin) <τ_0_0> (@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <τ_0_0>) -> @out AutoClosureWrapper<τ_0_0>
74113
}
75114

76115
// CHECK-LABEL: sil hidden [ossa] @$s26property_wrapper_parameter33testSimpleClosureWrapperParameteryyF : $@convention(thin) () -> ()

0 commit comments

Comments
 (0)