Skip to content

Commit 7cd8add

Browse files
committed
[ConstraintSystem] Add a property wrapper constraint to delay checking
if an inferred wrapper type is a property wrapper until that type is resolved.
1 parent f05589f commit 7cd8add

File tree

7 files changed

+121
-31
lines changed

7 files changed

+121
-31
lines changed

include/swift/Sema/Constraint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ enum class ConstraintKind : char {
187187
/// - If base is a protocol metatype, this constraint becomes a conformance
188188
/// check instead of an equality.
189189
UnresolvedMemberChainBase,
190+
/// The first type is a property wrapper with a wrapped-value type
191+
/// equal to the second type.
192+
PropertyWrapper,
190193
};
191194

192195
/// Classification of the different kinds of constraints.
@@ -586,6 +589,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
586589
case ConstraintKind::ValueMember:
587590
case ConstraintKind::UnresolvedValueMember:
588591
case ConstraintKind::ValueWitness:
592+
case ConstraintKind::PropertyWrapper:
589593
return ConstraintClassification::Member;
590594

591595
case ConstraintKind::DynamicTypeOf:

include/swift/Sema/ConstraintSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4595,6 +4595,11 @@ class ConstraintSystem {
45954595
ArrayRef<TypeVariableType *> referencedOuterParameters,
45964596
TypeMatchOptions flags, ConstraintLocatorBuilder locator);
45974597

4598+
/// Attempt to simplify a property wrapper constraint.
4599+
SolutionKind simplifyPropertyWrapperConstraint(Type wrapperType, Type wrappedValueType,
4600+
TypeMatchOptions flags,
4601+
ConstraintLocatorBuilder locator);
4602+
45984603
/// Attempt to simplify a one-way constraint.
45994604
SolutionKind simplifyOneWayConstraint(ConstraintKind kind,
46004605
Type first, Type second,

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,7 @@ void PotentialBindings::infer(Constraint *constraint) {
12511251
case ConstraintKind::FunctionInput:
12521252
case ConstraintKind::FunctionResult:
12531253
case ConstraintKind::OpaqueUnderlyingType:
1254+
case ConstraintKind::PropertyWrapper:
12541255
// Constraints from which we can't do anything.
12551256
break;
12561257

lib/Sema/CSGen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4104,6 +4104,12 @@ ConstraintSystem::applyPropertyWrapperToParameter(
41044104
if (argLabel.hasDollarPrefix()) {
41054105
Type projectionType = computeProjectedValueType(param, wrapperType);
41064106
addConstraint(matchKind, paramType, projectionType, locator);
4107+
if (param->hasImplicitPropertyWrapper()) {
4108+
auto wrappedValueType = getType(param->getPropertyWrapperWrappedValueVar());
4109+
addConstraint(ConstraintKind::PropertyWrapper, projectionType, wrappedValueType,
4110+
getConstraintLocator(param));
4111+
}
4112+
41074113
initKind = PropertyWrapperInitKind::ProjectedValue;
41084114
} else {
41094115
generateWrappedPropertyTypeConstraints(*this, wrapperType, param, paramType);

lib/Sema/CSSimplify.cpp

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
15681568
case ConstraintKind::OneWayBindParam:
15691569
case ConstraintKind::DefaultClosureType:
15701570
case ConstraintKind::UnresolvedMemberChainBase:
1571+
case ConstraintKind::PropertyWrapper:
15711572
llvm_unreachable("Not a conversion");
15721573
}
15731574

@@ -1706,6 +1707,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
17061707
case ConstraintKind::OneWayBindParam:
17071708
case ConstraintKind::DefaultClosureType:
17081709
case ConstraintKind::UnresolvedMemberChainBase:
1710+
case ConstraintKind::PropertyWrapper:
17091711
return true;
17101712
}
17111713

@@ -2096,6 +2098,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
20962098
case ConstraintKind::OneWayBindParam:
20972099
case ConstraintKind::DefaultClosureType:
20982100
case ConstraintKind::UnresolvedMemberChainBase:
2101+
case ConstraintKind::PropertyWrapper:
20992102
llvm_unreachable("Not a relational constraint");
21002103
}
21012104

@@ -5002,6 +5005,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
50025005
case ConstraintKind::OneWayBindParam:
50035006
case ConstraintKind::DefaultClosureType:
50045007
case ConstraintKind::UnresolvedMemberChainBase:
5008+
case ConstraintKind::PropertyWrapper:
50055009
llvm_unreachable("Not a relational constraint");
50065010
}
50075011
}
@@ -8104,6 +8108,58 @@ ConstraintSystem::simplifyDefaultClosureTypeConstraint(
81048108
return SolutionKind::Solved;
81058109
}
81068110

8111+
ConstraintSystem::SolutionKind
8112+
ConstraintSystem::simplifyPropertyWrapperConstraint(
8113+
Type wrapperType, Type wrappedValueType, TypeMatchOptions flags,
8114+
ConstraintLocatorBuilder locator) {
8115+
wrapperType = getFixedTypeRecursive(wrapperType, flags, /*wantRValue=*/true);
8116+
auto *loc = getConstraintLocator(locator);
8117+
8118+
if (wrapperType->isTypeVariableOrMember()) {
8119+
if (flags.contains(TMF_GenerateConstraints)) {
8120+
addUnsolvedConstraint(Constraint::create(
8121+
*this, ConstraintKind::PropertyWrapper, wrapperType, wrappedValueType, loc));
8122+
8123+
return SolutionKind::Solved;
8124+
}
8125+
8126+
return SolutionKind::Unsolved;
8127+
}
8128+
8129+
ConstraintFix *fix = nullptr;
8130+
8131+
// The wrapper type must be a property wrapper.
8132+
auto *nominal = wrapperType->getAnyNominal();
8133+
if (!(nominal && nominal->getAttrs().hasAttribute<PropertyWrapperAttr>())) {
8134+
if (auto *paramDecl = getAsDecl<ParamDecl>(locator.getAnchor())) {
8135+
fix = RemoveProjectedValueArgument::create(*this, wrapperType, paramDecl,
8136+
getConstraintLocator(paramDecl));
8137+
} else {
8138+
return SolutionKind::Error;
8139+
}
8140+
}
8141+
8142+
auto typeInfo = nominal->getPropertyWrapperTypeInfo();
8143+
if (!(typeInfo.projectedValueVar && typeInfo.hasProjectedValueInit)) {
8144+
if (auto *paramDecl = getAsDecl<ParamDecl>(locator.getAnchor())) {
8145+
fix = RemoveProjectedValueArgument::create(*this, wrapperType, paramDecl,
8146+
getConstraintLocator(paramDecl));
8147+
}
8148+
}
8149+
8150+
if (fix) {
8151+
if (!shouldAttemptFixes() || recordFix(fix))
8152+
return SolutionKind::Error;
8153+
8154+
return SolutionKind::Solved;
8155+
}
8156+
8157+
auto resolvedType = wrapperType->getTypeOfMember(DC->getParentModule(), typeInfo.valueVar);
8158+
addConstraint(ConstraintKind::Equal, wrappedValueType, resolvedType, locator);
8159+
8160+
return SolutionKind::Solved;
8161+
}
8162+
81078163
ConstraintSystem::SolutionKind
81088164
ConstraintSystem::simplifyOneWayConstraint(
81098165
ConstraintKind kind,
@@ -8272,51 +8328,36 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
82728328
}
82738329

82748330
if (paramDecl->hasAttachedPropertyWrapper()) {
8275-
bool hasError = false;
82768331
Type backingType;
8332+
Type wrappedValueType;
82778333

82788334
if (paramDecl->hasImplicitPropertyWrapper()) {
82798335
backingType = getContextualParamAt(i)->getPlainType();
8280-
8281-
// If the contextual type is not a property wrapper, record a fix.
8282-
auto *nominal = backingType->getAnyNominal();
8283-
if (!(nominal && nominal->getAttrs().hasAttribute<PropertyWrapperAttr>())) {
8284-
if (!shouldAttemptFixes())
8285-
return false;
8286-
8287-
paramDecl->visitAuxiliaryDecls([](VarDecl *var) {
8288-
var->setInvalid();
8289-
});
8290-
8291-
auto *fix = RemoveProjectedValueArgument::create(*this, backingType, paramDecl,
8292-
getConstraintLocator(paramDecl));
8293-
recordFix(fix);
8294-
hasError = true;
8295-
}
8336+
wrappedValueType = createTypeVariable(getConstraintLocator(locator), TVO_CanBindToHole);
82968337
} else {
82978338
auto *wrapperAttr = paramDecl->getAttachedPropertyWrappers().front();
82988339
auto wrapperType = paramDecl->getAttachedPropertyWrapperType(0);
82998340
backingType = replaceInferableTypesWithTypeVars(
83008341
wrapperType, getConstraintLocator(wrapperAttr->getTypeRepr()));
8342+
wrappedValueType = computeWrappedValueType(paramDecl, backingType);
83018343
}
83028344

8303-
if (!hasError) {
8304-
auto result = applyPropertyWrapperToParameter(backingType, param.getParameterType(),
8305-
paramDecl, paramDecl->getName(),
8306-
ConstraintKind::Equal, locator);
8307-
if (result.isFailure())
8308-
return false;
8309-
8310-
auto *backingVar = paramDecl->getPropertyWrapperBackingProperty();
8311-
setType(backingVar, backingType);
8345+
auto *backingVar = paramDecl->getPropertyWrapperBackingProperty();
8346+
setType(backingVar, backingType);
83128347

8313-
auto *localWrappedVar = paramDecl->getPropertyWrapperWrappedValueVar();
8314-
setType(localWrappedVar, computeWrappedValueType(paramDecl, backingType));
8348+
auto *localWrappedVar = paramDecl->getPropertyWrapperWrappedValueVar();
8349+
setType(localWrappedVar, wrappedValueType);
83158350

8316-
if (auto *projection = paramDecl->getPropertyWrapperProjectionVar()) {
8317-
setType(projection, computeProjectedValueType(paramDecl, backingType));
8318-
}
8351+
if (auto *projection = paramDecl->getPropertyWrapperProjectionVar()) {
8352+
setType(projection, computeProjectedValueType(paramDecl, backingType));
83198353
}
8354+
8355+
auto result = applyPropertyWrapperToParameter(backingType, param.getParameterType(),
8356+
paramDecl, paramDecl->getName(),
8357+
ConstraintKind::Equal,
8358+
getConstraintLocator(closure));
8359+
if (result.isFailure())
8360+
return false;
83208361
}
83218362

83228363
Type internalType;
@@ -11049,6 +11090,9 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1104911090
case ConstraintKind::Defaultable:
1105011091
return simplifyDefaultableConstraint(first, second, subflags, locator);
1105111092

11093+
case ConstraintKind::PropertyWrapper:
11094+
return simplifyPropertyWrapperConstraint(first, second, subflags, locator);
11095+
1105211096
case ConstraintKind::FunctionInput:
1105311097
case ConstraintKind::FunctionResult:
1105411098
return simplifyFunctionComponentConstraint(kind, first, second,
@@ -11563,6 +11607,12 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1156311607
/*flags*/ None,
1156411608
constraint.getLocator());
1156511609

11610+
case ConstraintKind::PropertyWrapper:
11611+
return simplifyPropertyWrapperConstraint(constraint.getFirstType(),
11612+
constraint.getSecondType(),
11613+
/*flags*/ None,
11614+
constraint.getLocator());
11615+
1156611616
case ConstraintKind::FunctionInput:
1156711617
case ConstraintKind::FunctionResult:
1156811618
return simplifyFunctionComponentConstraint(constraint.getKind(),

lib/Sema/Constraint.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
6868
case ConstraintKind::OneWayEqual:
6969
case ConstraintKind::OneWayBindParam:
7070
case ConstraintKind::UnresolvedMemberChainBase:
71+
case ConstraintKind::PropertyWrapper:
7172
assert(!First.isNull());
7273
assert(!Second.isNull());
7374
break;
@@ -144,6 +145,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
144145
case ConstraintKind::OneWayBindParam:
145146
case ConstraintKind::DefaultClosureType:
146147
case ConstraintKind::UnresolvedMemberChainBase:
148+
case ConstraintKind::PropertyWrapper:
147149
llvm_unreachable("Wrong constructor");
148150

149151
case ConstraintKind::KeyPath:
@@ -272,6 +274,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
272274
case ConstraintKind::OneWayBindParam:
273275
case ConstraintKind::DefaultClosureType:
274276
case ConstraintKind::UnresolvedMemberChainBase:
277+
case ConstraintKind::PropertyWrapper:
275278
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());
276279

277280
case ConstraintKind::ApplicableFunction:
@@ -370,6 +373,9 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
370373
case ConstraintKind::UnresolvedMemberChainBase:
371374
Out << " unresolved member chain base ";
372375
break;
376+
case ConstraintKind::PropertyWrapper:
377+
Out << " property wrapper with wrapped value of ";
378+
break;
373379
case ConstraintKind::KeyPath:
374380
Out << " key path from ";
375381
Out << getSecondType()->getString(PO);
@@ -597,6 +603,7 @@ gatherReferencedTypeVars(Constraint *constraint,
597603
case ConstraintKind::OneWayBindParam:
598604
case ConstraintKind::DefaultClosureType:
599605
case ConstraintKind::UnresolvedMemberChainBase:
606+
case ConstraintKind::PropertyWrapper:
600607
constraint->getFirstType()->getTypeVariables(typeVars);
601608
constraint->getSecondType()->getTypeVariables(typeVars);
602609
break;

test/Sema/property_wrapper_parameter.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,20 @@ func testImplicitPropertyWrapper() {
108108
(_value, value, $value)
109109
}
110110
}
111+
112+
@resultBuilder
113+
struct PairBuilder {
114+
static func buildBlock<T1, T2>(_ t1: T1, _ t2: T2) -> (T1, T2) {
115+
return (t1, t2)
116+
}
117+
}
118+
119+
func takesResultBuilder<Projection, T1, T2>(projection: Projection,
120+
@PairBuilder _ closure: (Projection) -> (T1, T2)) {}
121+
122+
func testResultBuilderWithImplicitWrapper(@ProjectionWrapper value: String) {
123+
takesResultBuilder(projection: $value) { $value in
124+
value
125+
$value
126+
}
127+
}

0 commit comments

Comments
 (0)