Skip to content

Commit 76c4c3d

Browse files
committed
[Diagnostics] Add back a dedicated fix/diagnostic for using an invalid
type as a property wrapper.
1 parent 7cd8add commit 76c4c3d

File tree

7 files changed

+88
-22
lines changed

7 files changed

+88
-22
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5575,7 +5575,8 @@ ERROR(property_wrapper_param_not_supported,none,
55755575
NOTE(property_wrapper_declared_here,none,
55765576
"property wrapper type %0 declared here", (Identifier))
55775577
ERROR(invalid_projection_argument,none,
5578-
"cannot use property wrapper projection argument", ())
5578+
"cannot use property wrapper projection %select{argument|parameter}0",
5579+
(bool))
55795580
NOTE(property_wrapper_param_no_wrapper,none,
55805581
"parameter %0 does not have an attached property wrapper", (Identifier))
55815582
NOTE(property_wrapper_param_attr_arg,none,

include/swift/Sema/CSFix.h

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

125+
/// Allow a type that is not a property wrapper to be used as a property
126+
/// wrapper.
127+
AllowInvalidPropertyWrapperType,
128+
125129
/// Remove the '$' prefix from an argument label or parameter name.
126130
RemoveProjectedValueArgument,
127131

@@ -980,6 +984,25 @@ class UseWrappedValue final : public ConstraintFix {
980984
ConstraintLocator *locator);
981985
};
982986

987+
class AllowInvalidPropertyWrapperType final : public ConstraintFix {
988+
Type wrapperType;
989+
990+
AllowInvalidPropertyWrapperType(ConstraintSystem &cs, Type wrapperType,
991+
ConstraintLocator *locator)
992+
: ConstraintFix(cs, FixKind::AllowInvalidPropertyWrapperType, locator),
993+
wrapperType(wrapperType) {}
994+
995+
public:
996+
static AllowInvalidPropertyWrapperType *create(ConstraintSystem &cs, Type wrapperType,
997+
ConstraintLocator *locator);
998+
999+
std::string getName() const override {
1000+
return "allow invalid property wrapper type";
1001+
}
1002+
1003+
bool diagnose(const Solution &solution, bool asNote = false) const override;
1004+
};
1005+
9831006
class RemoveProjectedValueArgument final : public ConstraintFix {
9841007
Type wrapperType;
9851008
ParamDecl *param;

lib/Sema/CSDiagnostics.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3312,20 +3312,33 @@ bool MissingPropertyWrapperUnwrapFailure::diagnoseAsError() {
33123312
return true;
33133313
}
33143314

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);
3322+
return true;
3323+
}
3324+
33153325
bool InvalidProjectedValueArgument::diagnoseAsError() {
3316-
if (param->hasImplicitPropertyWrapper()) {
3317-
emitDiagnostic(diag::invalid_implicit_property_wrapper, wrapperType);
3318-
} else {
3319-
emitDiagnostic(diag::invalid_projection_argument);
3326+
emitDiagnostic(diag::invalid_projection_argument, param->hasImplicitPropertyWrapper());
33203327

3321-
if (!param->hasAttachedPropertyWrapper()) {
3322-
param->diagnose(diag::property_wrapper_param_no_wrapper, param->getName());
3323-
} else if (param->getAttachedPropertyWrappers().front()->getArg()) {
3324-
param->diagnose(diag::property_wrapper_param_attr_arg);
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);
3333+
} else {
3334+
Type backingType;
3335+
if (param->hasImplicitPropertyWrapper()) {
3336+
backingType = getType(param->getPropertyWrapperBackingProperty());
33253337
} else {
3326-
auto backingType = param->getPropertyWrapperBackingPropertyType();
3327-
param->diagnose(diag::property_wrapper_no_init_projected_value, backingType);
3338+
backingType = param->getPropertyWrapperBackingPropertyType();
33283339
}
3340+
3341+
param->diagnose(diag::property_wrapper_no_init_projected_value, backingType);
33293342
}
33303343

33313344
return true;

lib/Sema/CSDiagnostics.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,17 @@ class MissingPropertyWrapperUnwrapFailure final
10791079
bool diagnoseAsError() override;
10801080
};
10811081

1082+
class InvalidPropertyWrapperType final : public FailureDiagnostic {
1083+
Type wrapperType;
1084+
1085+
public:
1086+
InvalidPropertyWrapperType(const Solution &solution, Type wrapper,
1087+
ConstraintLocator *locator)
1088+
: FailureDiagnostic(solution, locator), wrapperType(resolveType(wrapper)) {}
1089+
1090+
bool diagnoseAsError() override;
1091+
};
1092+
10821093
class InvalidProjectedValueArgument final : public FailureDiagnostic {
10831094
Type wrapperType;
10841095
ParamDecl *param;

lib/Sema/CSFix.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,17 @@ UseWrappedValue *UseWrappedValue::create(ConstraintSystem &cs,
646646
UseWrappedValue(cs, propertyWrapper, base, wrapper, locator);
647647
}
648648

649+
bool AllowInvalidPropertyWrapperType::diagnose(const Solution &solution, bool asNote) const {
650+
InvalidPropertyWrapperType failure(solution, wrapperType, getLocator());
651+
return failure.diagnose(asNote);
652+
}
653+
654+
AllowInvalidPropertyWrapperType *
655+
AllowInvalidPropertyWrapperType::create(ConstraintSystem &cs, Type wrapperType,
656+
ConstraintLocator *locator) {
657+
return new (cs.getAllocator()) AllowInvalidPropertyWrapperType(cs, wrapperType, locator);
658+
}
659+
649660
bool RemoveProjectedValueArgument::diagnose(const Solution &solution, bool asNote) const {
650661
InvalidProjectedValueArgument failure(solution, wrapperType, param, getLocator());
651662
return failure.diagnose(asNote);

lib/Sema/CSSimplify.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8127,23 +8127,23 @@ ConstraintSystem::simplifyPropertyWrapperConstraint(
81278127
}
81288128

81298129
ConstraintFix *fix = nullptr;
8130+
auto *wrappedVar = getAsDecl<VarDecl>(locator.getAnchor());
8131+
assert(wrappedVar && wrappedVar->hasAttachedPropertyWrapper());
81308132

81318133
// The wrapper type must be a property wrapper.
8132-
auto *nominal = wrapperType->getAnyNominal();
8134+
auto *nominal = wrapperType->getDesugaredType()->getAnyNominal();
81338135
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-
}
8136+
fix = AllowInvalidPropertyWrapperType::create(*this, wrapperType,
8137+
getConstraintLocator(locator));
81408138
}
81418139

81428140
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));
8141+
8142+
// Implicit property wrappers must support projected-value initialization.
8143+
if (!fix && wrappedVar->hasImplicitPropertyWrapper()) {
8144+
if (!(typeInfo.projectedValueVar && typeInfo.hasProjectedValueInit)) {
8145+
fix = RemoveProjectedValueArgument::create(*this, wrapperType, cast<ParamDecl>(wrappedVar),
8146+
getConstraintLocator(locator));
81478147
}
81488148
}
81498149

@@ -10833,6 +10833,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1083310833
case FixKind::SkipUnhandledConstructInResultBuilder:
1083410834
case FixKind::UsePropertyWrapper:
1083510835
case FixKind::UseWrappedValue:
10836+
case FixKind::AllowInvalidPropertyWrapperType:
1083610837
case FixKind::RemoveProjectedValueArgument:
1083710838
case FixKind::ExpandArrayIntoVarargs:
1083810839
case FixKind::UseRawValue:

test/Sema/property_wrapper_parameter_invalid.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ func testNoProjection(message: String) {
4141

4242
// expected-error@+1 {{cannot use property wrapper projection argument}}
4343
takesNoProjectionWrapper($value: message)
44+
45+
// expected-error@+2 {{cannot use property wrapper projection parameter}}
46+
// expected-note@+1 {{property wrapper type 'NoProjection<Int>' does not support initialization from a projected value}}
47+
let _: (NoProjection<Int>) -> Int = { $value in
48+
return value
49+
}
4450
}
4551

4652
struct Projection<T> {

0 commit comments

Comments
 (0)