Skip to content

Commit 6f4b62a

Browse files
authored
Merge pull request swiftlang#36568 from hborla/property-wrapper-constraint
[ConstraintSystem] Add a property-wrapper constraint to allow for inference of implicit property wrappers
2 parents ad02d91 + ee2a8fc commit 6f4b62a

16 files changed

+243
-138
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5581,16 +5581,16 @@ ERROR(property_wrapper_param_not_supported,none,
55815581
(DescriptiveDeclKind))
55825582
NOTE(property_wrapper_declared_here,none,
55835583
"property wrapper type %0 declared here", (Identifier))
5584-
ERROR(property_wrapper_param_no_projection,none,
5585-
"cannot use property wrapper projection parameter; "
5586-
"wrapper %0 does not have a 'projectedValue'", (Type))
5587-
ERROR(property_wrapper_param_no_wrapper,none,
5588-
"cannot use property wrapper projection argument; "
5589-
"parameter does not have an attached property wrapper",
5590-
())
5591-
ERROR(property_wrapper_param_projection_invalid,none,
5592-
"cannot use property wrapper projection argument; "
5593-
"pass wrapped value type %0 instead", (Type))
5584+
ERROR(invalid_projection_argument,none,
5585+
"cannot use property wrapper projection %select{argument|parameter}0",
5586+
(bool))
5587+
NOTE(property_wrapper_param_no_wrapper,none,
5588+
"parameter %0 does not have an attached property wrapper", (Identifier))
5589+
NOTE(property_wrapper_param_attr_arg,none,
5590+
"property wrapper has arguments in the wrapper attribute", ())
5591+
NOTE(property_wrapper_no_init_projected_value,none,
5592+
"property wrapper type %0 does not support initialization from a "
5593+
"projected value", (Type))
55945594
ERROR(property_wrapper_param_mutating,none,
55955595
"property wrapper applied to parameter must have a nonmutating "
55965596
"'wrappedValue' getter", ())

include/swift/AST/Types.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,7 +3329,7 @@ END_CAN_TYPE_WRAPPER(FunctionType, AnyFunctionType)
33293329
struct ParameterListInfo {
33303330
SmallBitVector defaultArguments;
33313331
SmallBitVector acceptsUnlabeledTrailingClosures;
3332-
SmallVector<const ParamDecl *, 4> propertyWrappers;
3332+
SmallBitVector propertyWrappers;
33333333

33343334
public:
33353335
ParameterListInfo() { }
@@ -3346,7 +3346,7 @@ struct ParameterListInfo {
33463346

33473347
/// The ParamDecl at the given index if the parameter has an applied
33483348
/// property wrapper.
3349-
const ParamDecl *getPropertyWrapperParam(unsigned paramIdx) const;
3349+
bool hasExternalPropertyWrapper(unsigned paramIdx) const;
33503350

33513351
/// Retrieve the number of non-defaulted parameters.
33523352
unsigned numNonDefaultedParameters() const {

include/swift/Sema/CSFix.h

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,12 @@ enum class FixKind : uint8_t {
122122
/// the storage or property wrapper.
123123
UseWrappedValue,
124124

125-
/// Add 'var projectedValue' to the property wrapper type to allow passing
126-
/// a projection argument.
127-
AddProjectedValue,
125+
/// Allow a type that is not a property wrapper to be used as a property
126+
/// wrapper.
127+
AllowInvalidPropertyWrapperType,
128128

129-
/// Add '@propertyWrapper' to a nominal type declaration.
130-
AddPropertyWrapperAttribute,
129+
/// Remove the '$' prefix from an argument label or parameter name.
130+
RemoveProjectedValueArgument,
131131

132132
/// Instead of spelling out `subscript` directly, use subscript operator.
133133
UseSubscriptOperator,
@@ -984,37 +984,40 @@ class UseWrappedValue final : public ConstraintFix {
984984
ConstraintLocator *locator);
985985
};
986986

987-
class AddProjectedValue final : public ConstraintFix {
987+
class AllowInvalidPropertyWrapperType final : public ConstraintFix {
988988
Type wrapperType;
989989

990-
AddProjectedValue(ConstraintSystem &cs, Type wrapper,
991-
ConstraintLocator *locator)
992-
: ConstraintFix(cs, FixKind::AddProjectedValue, locator), wrapperType(wrapper) {}
990+
AllowInvalidPropertyWrapperType(ConstraintSystem &cs, Type wrapperType,
991+
ConstraintLocator *locator)
992+
: ConstraintFix(cs, FixKind::AllowInvalidPropertyWrapperType, locator),
993+
wrapperType(wrapperType) {}
993994

994995
public:
995-
static AddProjectedValue *create(ConstraintSystem &cs, Type wrapper,
996-
ConstraintLocator *locator);
996+
static AllowInvalidPropertyWrapperType *create(ConstraintSystem &cs, Type wrapperType,
997+
ConstraintLocator *locator);
997998

998999
std::string getName() const override {
999-
return "add 'var projectedValue' to pass a projection argument";
1000+
return "allow invalid property wrapper type";
10001001
}
10011002

10021003
bool diagnose(const Solution &solution, bool asNote = false) const override;
10031004
};
10041005

1005-
class AddPropertyWrapperAttribute final : public ConstraintFix {
1006+
class RemoveProjectedValueArgument final : public ConstraintFix {
10061007
Type wrapperType;
1008+
ParamDecl *param;
10071009

1008-
AddPropertyWrapperAttribute(ConstraintSystem &cs, Type wrapper,
1009-
ConstraintLocator *locator)
1010-
: ConstraintFix(cs, FixKind::AddPropertyWrapperAttribute, locator), wrapperType(wrapper) {}
1010+
RemoveProjectedValueArgument(ConstraintSystem &cs, Type wrapper,
1011+
ParamDecl *param, ConstraintLocator *locator)
1012+
: ConstraintFix(cs, FixKind::RemoveProjectedValueArgument, locator),
1013+
wrapperType(wrapper), param(param) {}
10111014

10121015
public:
1013-
static AddPropertyWrapperAttribute *create(ConstraintSystem &cs, Type wrapper,
1014-
ConstraintLocator *locator);
1016+
static RemoveProjectedValueArgument *create(ConstraintSystem &cs, Type wrapper,
1017+
ParamDecl *param, ConstraintLocator *locator);
10151018

10161019
std::string getName() const override {
1017-
return "add '@propertyWrapper'";
1020+
return "remove '$' from argument label";
10181021
}
10191022

10201023
bool diagnose(const Solution &solution, bool asNote = false) const override;

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/AST/Type.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,7 @@ ParameterListInfo::ParameterListInfo(
967967
}
968968

969969
if (param->hasAttachedPropertyWrapper()) {
970-
propertyWrappers[i] = param;
970+
propertyWrappers.set(i);
971971
}
972972
}
973973
}
@@ -983,9 +983,8 @@ bool ParameterListInfo::acceptsUnlabeledTrailingClosureArgument(
983983
acceptsUnlabeledTrailingClosures[paramIdx];
984984
}
985985

986-
const ParamDecl *
987-
ParameterListInfo::getPropertyWrapperParam(unsigned paramIdx) const {
988-
return paramIdx < propertyWrappers.size() ? propertyWrappers[paramIdx] : nullptr;
986+
bool ParameterListInfo::hasExternalPropertyWrapper(unsigned paramIdx) const {
987+
return paramIdx < propertyWrappers.size() ? propertyWrappers[paramIdx] : false;
989988
}
990989

991990
/// Turn a param list into a symbolic and printable representation that does not

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5953,7 +5953,8 @@ Expr *ExprRewriter::coerceCallArguments(
59535953
return true;
59545954
};
59555955

5956-
if (auto *param = paramInfo.getPropertyWrapperParam(paramIdx)) {
5956+
if (paramInfo.hasExternalPropertyWrapper(paramIdx)) {
5957+
auto *param = getParameterAt(callee.getDecl(), paramIdx);
59575958
auto appliedWrapper = appliedPropertyWrappers[appliedWrapperIndex++];
59585959
auto wrapperType = solution.simplifyType(appliedWrapper.wrapperType);
59595960
auto initKind = appliedWrapper.initKind;

lib/Sema/CSBindings.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,8 @@ void PotentialBindings::infer(Constraint *constraint) {
13131313

13141314
case ConstraintKind::ValueMember:
13151315
case ConstraintKind::UnresolvedValueMember:
1316-
case ConstraintKind::ValueWitness: {
1316+
case ConstraintKind::ValueWitness:
1317+
case ConstraintKind::PropertyWrapper: {
13171318
// If current type variable represents a member type of some reference,
13181319
// it would be bound once member is resolved either to a actual member
13191320
// type or to a hole if member couldn't be found.

lib/Sema/CSDiagnostics.cpp

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3306,32 +3306,39 @@ bool MissingPropertyWrapperUnwrapFailure::diagnoseAsError() {
33063306
return true;
33073307
}
33083308

3309-
if (isa<ParamDecl>(getProperty())) {
3310-
auto wrapperType = getToType();
3311-
auto wrappedValueType = computeWrappedValueType(getProperty(), wrapperType);
3312-
emitDiagnostic(diag::property_wrapper_param_projection_invalid, wrappedValueType);
3313-
return true;
3314-
}
3315-
33163309
emitDiagnostic(diag::incorrect_property_wrapper_reference, getPropertyName(),
33173310
getFromType(), getToType(), true)
33183311
.fixItRemoveChars(getLoc(), endLoc);
33193312
return true;
33203313
}
33213314

3322-
bool MissingProjectedValueFailure::diagnoseAsError() {
3323-
emitDiagnostic(diag::property_wrapper_param_no_projection, wrapperType);
3315+
bool InvalidPropertyWrapperType::diagnoseAsError() {
3316+
// The property wrapper constraint is currently only used for
3317+
// implicit property wrappers on closure parameters.
3318+
auto *wrappedVar = getAsDecl<VarDecl>(getAnchor());
3319+
assert(wrappedVar->hasImplicitPropertyWrapper());
3320+
3321+
emitDiagnostic(diag::invalid_implicit_property_wrapper, wrapperType);
33243322
return true;
33253323
}
33263324

3327-
bool MissingPropertyWrapperAttributeFailure::diagnoseAsError() {
3328-
if (auto *param = getAsDecl<ParamDecl>(getAnchor())) {
3329-
emitDiagnostic(diag::invalid_implicit_property_wrapper, wrapperType);
3325+
bool InvalidProjectedValueArgument::diagnoseAsError() {
3326+
emitDiagnostic(diag::invalid_projection_argument, param->hasImplicitPropertyWrapper());
33303327

3331-
// FIXME: emit a note and fix-it to add '@propertyWrapper' if the
3332-
// type is a nominal and in the same module.
3328+
if (!param->hasAttachedPropertyWrapper()) {
3329+
param->diagnose(diag::property_wrapper_param_no_wrapper, param->getName());
3330+
} else if (!param->hasImplicitPropertyWrapper() &&
3331+
param->getAttachedPropertyWrappers().front()->getArg()) {
3332+
param->diagnose(diag::property_wrapper_param_attr_arg);
33333333
} else {
3334-
emitDiagnostic(diag::property_wrapper_param_no_wrapper);
3334+
Type backingType;
3335+
if (param->hasImplicitPropertyWrapper()) {
3336+
backingType = getType(param->getPropertyWrapperBackingProperty());
3337+
} else {
3338+
backingType = param->getPropertyWrapperBackingPropertyType();
3339+
}
3340+
3341+
param->diagnose(diag::property_wrapper_no_init_projected_value, backingType);
33353342
}
33363343

33373344
return true;

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,24 +1079,26 @@ class MissingPropertyWrapperUnwrapFailure final
10791079
bool diagnoseAsError() override;
10801080
};
10811081

1082-
class MissingProjectedValueFailure final : public FailureDiagnostic {
1082+
class InvalidPropertyWrapperType final : public FailureDiagnostic {
10831083
Type wrapperType;
10841084

10851085
public:
1086-
MissingProjectedValueFailure(const Solution &solution, Type wrapper,
1087-
ConstraintLocator *locator)
1086+
InvalidPropertyWrapperType(const Solution &solution, Type wrapper,
1087+
ConstraintLocator *locator)
10881088
: FailureDiagnostic(solution, locator), wrapperType(resolveType(wrapper)) {}
10891089

10901090
bool diagnoseAsError() override;
10911091
};
10921092

1093-
class MissingPropertyWrapperAttributeFailure final : public FailureDiagnostic {
1093+
class InvalidProjectedValueArgument final : public FailureDiagnostic {
10941094
Type wrapperType;
1095+
ParamDecl *param;
10951096

10961097
public:
1097-
MissingPropertyWrapperAttributeFailure(const Solution &solution, Type wrapper,
1098-
ConstraintLocator *locator)
1099-
: FailureDiagnostic(solution, locator), wrapperType(resolveType(wrapper)) {}
1098+
InvalidProjectedValueArgument(const Solution &solution, Type wrapper,
1099+
ParamDecl *param, ConstraintLocator *locator)
1100+
: FailureDiagnostic(solution, locator), wrapperType(resolveType(wrapper)),
1101+
param(param) {}
11001102

11011103
bool diagnoseAsError() override;
11021104
};

0 commit comments

Comments
 (0)