Skip to content

Commit a5d8c33

Browse files
authored
Merge pull request #38892 from hborla/5.5-wrapped-argument-conversions
[5.5][Property Wrappers] Fix a bug where wrapped arguments were not properly coerced to the wrapper generator input type.
2 parents d3cf72b + 203c304 commit a5d8c33

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
@@ -1695,6 +1695,10 @@ class SolutionApplicationTarget {
16951695
static SolutionApplicationTarget forUninitializedWrappedVar(
16961696
VarDecl *wrappedVar);
16971697

1698+
/// Form a target for a synthesized property wrapper initializer.
1699+
static SolutionApplicationTarget forPropertyWrapperInitializer(
1700+
VarDecl *wrappedVar, DeclContext *dc, Expr *initializer);
1701+
16981702
Expr *getAsExpr() const {
16991703
switch (kind) {
17001704
case Kind::expression:
@@ -1802,7 +1806,7 @@ class SolutionApplicationTarget {
18021806
bool isOptionalSomePatternInit() const {
18031807
return kind == Kind::expression &&
18041808
expression.contextualPurpose == CTP_Initialization &&
1805-
isa<OptionalSomePattern>(expression.pattern) &&
1809+
dyn_cast_or_null<OptionalSomePattern>(expression.pattern) &&
18061810
!expression.pattern->isImplicit();
18071811
}
18081812

@@ -1826,7 +1830,9 @@ class SolutionApplicationTarget {
18261830

18271831
// Don't create property wrapper generator functions for static variables and
18281832
// local variables with initializers.
1829-
if (wrappedVar->isStatic() || wrappedVar->getDeclContext()->isLocalContext())
1833+
bool hasInit = expression.propertyWrapper.hasInitialWrappedValue;
1834+
if (wrappedVar->isStatic() ||
1835+
(hasInit && wrappedVar->getDeclContext()->isLocalContext()))
18301836
return false;
18311837

18321838
return expression.propertyWrapper.innermostWrappedValueInit == apply;

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,10 +2128,10 @@ void ASTMangler::appendContext(const DeclContext *ctx, StringRef useModuleName)
21282128
auto wrapperInit = cast<PropertyWrapperInitializer>(ctx);
21292129
switch (wrapperInit->getKind()) {
21302130
case PropertyWrapperInitializer::Kind::WrappedValue:
2131-
appendBackingInitializerEntity(wrapperInit->getParam());
2131+
appendBackingInitializerEntity(wrapperInit->getWrappedVar());
21322132
break;
21332133
case PropertyWrapperInitializer::Kind::ProjectedValue:
2134-
appendInitFromProjectedValueEntity(wrapperInit->getParam());
2134+
appendInitFromProjectedValueEntity(wrapperInit->getWrappedVar());
21352135
break;
21362136
}
21372137
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
@@ -1297,8 +1297,8 @@ class ExprContextAnalyzer {
12971297
auto AFD = dyn_cast<AbstractFunctionDecl>(initDC->getParent());
12981298
if (!AFD)
12991299
return;
1300-
auto *param = initDC->getParam();
1301-
recordPossibleType(AFD->mapTypeIntoContext(param->getInterfaceType()));
1300+
auto *var = initDC->getWrappedVar();
1301+
recordPossibleType(AFD->mapTypeIntoContext(var->getInterfaceType()));
13021302
break;
13031303
}
13041304
}

lib/Sema/CSApply.cpp

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

60236023
if (paramInfo.hasExternalPropertyWrapper(paramIdx)) {
6024-
auto *param = getParameterAt(callee.getDecl(), paramIdx);
6024+
auto *paramDecl = getParameterAt(callee.getDecl(), paramIdx);
60256025
auto appliedWrapper = appliedPropertyWrappers[appliedWrapperIndex++];
60266026
auto wrapperType = solution.simplifyType(appliedWrapper.wrapperType);
60276027
auto initKind = appliedWrapper.initKind;
60286028

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

6033-
arg = AppliedPropertyWrapperExpr::create(ctx, callee, param, arg->getStartLoc(),
6056+
arg = coerceToType(arg, generatorInputType, argLoc);
6057+
6058+
// Wrap the argument in an applied property wrapper expr, which will
6059+
// later turn into a call to the property wrapper generator function.
6060+
arg = AppliedPropertyWrapperExpr::create(ctx, callee, paramDecl,
6061+
arg->getStartLoc(),
60346062
wrapperType, arg, valueKind);
60356063
cs.cacheExprTypes(arg);
60366064
}
@@ -8404,13 +8432,18 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
84048432
// been subsumed by the backing property.
84058433
if (wrappedVar) {
84068434
ASTContext &ctx = cs.getASTContext();
8407-
wrappedVar->getParentPatternBinding()->setInitializerSubsumed(0);
84088435
ctx.setSideCachedPropertyWrapperBackingPropertyType(
84098436
wrappedVar, initType->mapTypeOutOfContext());
84108437

84118438
// Record the semantic initializer on the outermost property wrapper.
84128439
wrappedVar->getAttachedPropertyWrappers().front()
84138440
->setSemanticInit(initializer);
8441+
8442+
// If this is a wrapped parameter, we're done.
8443+
if (isa<ParamDecl>(wrappedVar))
8444+
return resultTarget;
8445+
8446+
wrappedVar->getParentPatternBinding()->setInitializerSubsumed(0);
84148447
}
84158448

84168449
// 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
@@ -5102,7 +5102,14 @@ SolutionApplicationTarget::SolutionApplicationTarget(
51025102
void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
51035103
assert(kind == Kind::expression);
51045104
assert(expression.contextualPurpose == CTP_Initialization);
5105-
auto singleVar = expression.pattern->getSingleVar();
5105+
5106+
VarDecl *singleVar;
5107+
if (auto *pattern = expression.pattern) {
5108+
singleVar = pattern->getSingleVar();
5109+
} else {
5110+
singleVar = expression.propertyWrapper.wrappedVar;
5111+
}
5112+
51065113
if (!singleVar)
51075114
return;
51085115

@@ -5232,6 +5239,23 @@ SolutionApplicationTarget::forUninitializedWrappedVar(VarDecl *wrappedVar) {
52325239
return SolutionApplicationTarget(wrappedVar);
52335240
}
52345241

5242+
SolutionApplicationTarget
5243+
SolutionApplicationTarget::forPropertyWrapperInitializer(
5244+
VarDecl *wrappedVar, DeclContext *dc, Expr *initializer) {
5245+
SolutionApplicationTarget target(
5246+
initializer, dc, CTP_Initialization, wrappedVar->getType(),
5247+
/*isDiscarded=*/false);
5248+
target.expression.propertyWrapper.wrappedVar = wrappedVar;
5249+
if (auto *patternBinding = wrappedVar->getParentPatternBinding()) {
5250+
auto index = patternBinding->getPatternEntryIndexForVarDecl(wrappedVar);
5251+
target.expression.initialization.patternBinding = patternBinding;
5252+
target.expression.initialization.patternBindingIndex = index;
5253+
target.expression.pattern = patternBinding->getPattern(index);
5254+
}
5255+
target.maybeApplyPropertyWrapper();
5256+
return target;
5257+
}
5258+
52355259
ContextualPattern
52365260
SolutionApplicationTarget::getContextualPattern() const {
52375261
assert(kind == Kind::expression);

lib/Sema/TypeCheckAvailability.cpp

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

118120
case DeclContextKind::SubscriptDecl:

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,8 +2597,8 @@ void swift::checkEnumElementActorIsolation(
25972597
}
25982598

25992599
void swift::checkPropertyWrapperActorIsolation(
2600-
PatternBindingDecl *binding, Expr *expr) {
2601-
ActorIsolationChecker checker(binding->getDeclContext());
2600+
VarDecl *wrappedVar, Expr *expr) {
2601+
ActorIsolationChecker checker(wrappedVar->getDeclContext());
26022602
expr->walk(checker);
26032603
}
26042604

lib/Sema/TypeCheckConcurrency.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class ProtocolConformance;
4444
class TopLevelCodeDecl;
4545
class TypeBase;
4646
class ValueDecl;
47+
class VarDecl;
4748

4849
/// Add notes suggesting the addition of 'async' or '@asyncHandler', as
4950
/// appropriate, to a diagnostic for a function that isn't an async context.
@@ -54,8 +55,7 @@ void checkTopLevelActorIsolation(TopLevelCodeDecl *decl);
5455
void checkFunctionActorIsolation(AbstractFunctionDecl *decl);
5556
void checkInitializerActorIsolation(Initializer *init, Expr *expr);
5657
void checkEnumElementActorIsolation(EnumElementDecl *element, Expr *expr);
57-
void checkPropertyWrapperActorIsolation(
58-
PatternBindingDecl *binding, Expr *expr);
58+
void checkPropertyWrapperActorIsolation(VarDecl *wrappedVar, Expr *expr);
5959

6060
/// Determine the isolation of a particular closure.
6161
///

lib/Sema/TypeCheckStorage.cpp

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

25722572
static void typeCheckSynthesizedWrapperInitializer(VarDecl *wrappedVar,
25732573
Expr *&initializer) {
2574-
// Figure out the context in which the initializer was written.
2575-
auto *parentPBD = wrappedVar->getParentPatternBinding();
2576-
auto i = parentPBD->getPatternEntryIndexForVarDecl(wrappedVar);
2577-
DeclContext *originalDC = parentPBD->getDeclContext();
2578-
if (!originalDC->isLocalContext()) {
2579-
auto initContext =
2580-
cast_or_null<PatternBindingInitializer>(parentPBD->getInitContext(i));
2581-
if (initContext)
2582-
originalDC = initContext;
2583-
}
2574+
auto *dc = wrappedVar->getInnermostDeclContext();
2575+
auto &ctx = wrappedVar->getASTContext();
2576+
auto *initContext = new (ctx) PropertyWrapperInitializer(
2577+
dc, wrappedVar, PropertyWrapperInitializer::Kind::WrappedValue);
25842578

25852579
// Type-check the initialization.
2586-
auto *pattern = parentPBD->getPattern(i);
2587-
TypeChecker::typeCheckBinding(pattern, initializer, originalDC,
2588-
wrappedVar->getType(), parentPBD, i);
2580+
using namespace constraints;
2581+
auto target = SolutionApplicationTarget::forPropertyWrapperInitializer(
2582+
wrappedVar, initContext, initializer);
2583+
auto result = TypeChecker::typeCheckExpression(target);
2584+
if (!result)
2585+
return;
25892586

2590-
if (auto initializerContext =
2591-
dyn_cast_or_null<Initializer>(parentPBD->getInitContext(i))) {
2592-
TypeChecker::contextualizeInitializer(initializerContext, initializer);
2593-
}
2587+
initializer = result->getAsExpr();
25942588

2595-
auto *backingVar = wrappedVar->getPropertyWrapperBackingProperty();
2596-
auto *backingPBD = backingVar->getParentPatternBinding();
2597-
checkPropertyWrapperActorIsolation(backingPBD, initializer);
2598-
TypeChecker::checkPropertyWrapperEffects(backingPBD, initializer);
2589+
TypeChecker::contextualizeInitializer(initContext, initializer);
2590+
checkPropertyWrapperActorIsolation(wrappedVar, initializer);
2591+
TypeChecker::checkInitializerEffects(initContext, initializer);
25992592
}
26002593

26012594
static PropertyWrapperMutability::Value
@@ -2954,21 +2947,7 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
29542947
!var->getName().hasDollarPrefix()) {
29552948
wrappedValueInit = PropertyWrapperValuePlaceholderExpr::create(
29562949
ctx, var->getSourceRange(), var->getType(), /*wrappedValue=*/nullptr);
2957-
2958-
if (auto *param = dyn_cast<ParamDecl>(var)) {
2959-
wrappedValueInit = buildPropertyWrapperInitCall(
2960-
var, storageType, wrappedValueInit, PropertyWrapperInitKind::WrappedValue);
2961-
TypeChecker::typeCheckExpression(wrappedValueInit, dc);
2962-
2963-
// Check initializer effects.
2964-
auto *initContext = new (ctx) PropertyWrapperInitializer(
2965-
dc, param, PropertyWrapperInitializer::Kind::WrappedValue);
2966-
TypeChecker::contextualizeInitializer(initContext, wrappedValueInit);
2967-
checkInitializerActorIsolation(initContext, wrappedValueInit);
2968-
TypeChecker::checkInitializerEffects(initContext, wrappedValueInit);
2969-
} else {
2970-
typeCheckSynthesizedWrapperInitializer(var, wrappedValueInit);
2971-
}
2950+
typeCheckSynthesizedWrapperInitializer(var, wrappedValueInit);
29722951
}
29732952

29742953
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)