Skip to content

Commit 28ab5ce

Browse files
authored
Merge pull request #31876 from hborla/property-wrapper-composition-inference
[Property Wrappers] Adjust composed property wrapper constraint generation
2 parents b2a8ff5 + 392a263 commit 28ab5ce

File tree

2 files changed

+70
-13
lines changed

2 files changed

+70
-13
lines changed

lib/Sema/CSGen.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4209,26 +4209,35 @@ static Expr *generateConstraintsFor(ConstraintSystem &cs, Expr *expr,
42094209
static Type generateWrappedPropertyTypeConstraints(
42104210
ConstraintSystem &cs, Type initializerType,
42114211
VarDecl *wrappedVar, ConstraintLocator *locator) {
4212-
Type valueType = LValueType::get(initializerType);
42134212
auto dc = wrappedVar->getInnermostDeclContext();
42144213

4214+
Type wrapperType = LValueType::get(initializerType);
4215+
Type wrappedValueType;
4216+
42154217
for (unsigned i : indices(wrappedVar->getAttachedPropertyWrappers())) {
4218+
Type rawWrapperType = wrappedVar->getAttachedPropertyWrapperType(i);
4219+
if (!rawWrapperType || rawWrapperType->hasError())
4220+
return Type();
4221+
4222+
// The former wrappedValue type must be equal to the current wrapper type
4223+
if (wrappedValueType) {
4224+
wrapperType = cs.openUnboundGenericTypes(rawWrapperType, locator);
4225+
cs.addConstraint(ConstraintKind::Equal, wrappedValueType, wrapperType,
4226+
locator);
4227+
}
4228+
42164229
auto wrapperInfo = wrappedVar->getAttachedPropertyWrapperTypeInfo(i);
42174230
if (!wrapperInfo)
4218-
break;
4219-
4220-
locator = cs.getConstraintLocator(locator, ConstraintLocator::Member);
4221-
Type memberType = cs.createTypeVariable(locator, TVO_CanBindToLValue);
4222-
cs.addValueMemberConstraint(
4223-
valueType, wrapperInfo.valueVar->createNameRef(),
4224-
memberType, dc, FunctionRefKind::Unapplied, { }, locator);
4225-
valueType = memberType;
4231+
return Type();
4232+
4233+
wrappedValueType = wrapperType->getTypeOfMember(
4234+
dc->getParentModule(), wrapperInfo.valueVar);
42264235
}
42274236

42284237
// Set up an equality constraint to drop the lvalue-ness of the value
42294238
// type we produced.
42304239
Type propertyType = cs.createTypeVariable(locator, 0);
4231-
cs.addConstraint(ConstraintKind::Equal, propertyType, valueType, locator);
4240+
cs.addConstraint(ConstraintKind::Equal, propertyType, wrappedValueType, locator);
42324241
return propertyType;
42334242
}
42344243

@@ -4245,10 +4254,13 @@ static bool generateInitPatternConstraints(
42454254
assert(patternType && "All patterns have a type");
42464255

42474256
if (auto wrappedVar = target.getInitializationWrappedVar()) {
4248-
// Add an equal constraint between the pattern type and the
4249-
// property wrapper's "value" type.
42504257
Type propertyType = generateWrappedPropertyTypeConstraints(
42514258
cs, cs.getType(target.getAsExpr()), wrappedVar, locator);
4259+
if (!propertyType)
4260+
return true;
4261+
4262+
// Add an equal constraint between the pattern type and the
4263+
// property wrapper's "value" type.
42524264
cs.addConstraint(ConstraintKind::Equal, patternType,
42534265
propertyType, locator, /*isFavored*/ true);
42544266
} else if (!patternType->is<OpaqueTypeArchetypeType>()) {

test/decl/var/property_wrappers.swift

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ struct MultipleWrappers {
219219
// attempting to splice a 'wrappedValue:' argument into the call to Wrapper's
220220
// init, but it doesn't have a matching init. We're then attempting to access
221221
// the nested 'wrappedValue', but Wrapper's 'wrappedValue' is Int.
222-
@Wrapper(stored: 17) // expected-error{{value of type 'Int' has no member 'wrappedValue'}}
222+
@Wrapper(stored: 17) // expected-error{{cannot convert value of type 'Int' to expected argument type 'WrapperWithInitialValue<Int>'}}
223223
@WrapperWithInitialValue // expected-error{{extra argument 'wrappedValue' in call}}
224224
var x: Int = 17
225225

@@ -1069,6 +1069,51 @@ struct TestComposition {
10691069
}
10701070
}
10711071

1072+
// ---------------------------------------------------------------------------
1073+
// Property wrapper composition type inference
1074+
// ---------------------------------------------------------------------------
1075+
1076+
protocol DefaultValue {
1077+
static var defaultValue: Self { get }
1078+
}
1079+
1080+
extension Int: DefaultValue {
1081+
static var defaultValue: Int { 0 }
1082+
}
1083+
1084+
struct TestCompositionTypeInference {
1085+
@propertyWrapper
1086+
struct A<Value: DefaultValue> {
1087+
var wrappedValue: Value
1088+
1089+
init(wrappedValue: Value = .defaultValue, key: String) {
1090+
self.wrappedValue = wrappedValue
1091+
}
1092+
}
1093+
1094+
@propertyWrapper
1095+
struct B<Value: DefaultValue>: DefaultValue {
1096+
var wrappedValue: Value
1097+
1098+
init(wrappedValue: Value = .defaultValue) {
1099+
self.wrappedValue = wrappedValue
1100+
}
1101+
1102+
static var defaultValue: B<Value> { B() }
1103+
}
1104+
1105+
// All of these are okay
1106+
1107+
@A(key: "b") @B
1108+
var a: Int = 0
1109+
1110+
@A(key: "b") @B
1111+
var b: Int
1112+
1113+
@A(key: "c") @B @B
1114+
var c: Int
1115+
}
1116+
10721117
// ---------------------------------------------------------------------------
10731118
// Missing Property Wrapper Unwrap Diagnostics
10741119
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)