Skip to content

Commit 522eedc

Browse files
committed
[ConstraintSystem] Emit an error message when trying to pass a property
wrapper projection argument to a wrapped parameter with arguments in the wrapper attribute.
1 parent 12161fa commit 522eedc

File tree

5 files changed

+51
-12
lines changed

5 files changed

+51
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5484,12 +5484,12 @@ ERROR(property_wrapper_attribute_not_on_property, none,
54845484
(Identifier))
54855485
NOTE(property_wrapper_declared_here,none,
54865486
"property wrapper type %0 declared here", (Identifier))
5487-
ERROR(property_wrapper_param_arg, none,
5488-
"property wrapper attributes applied to parameters cannot have arguments",
5489-
())
54905487
ERROR(property_wrapper_param_no_projection,none,
54915488
"cannot use property wrapper projection parameter; "
54925489
"wrapper %0 does not have a 'projectedValue'", (Type))
5490+
ERROR(property_wrapper_param_projection_invalid,none,
5491+
"cannot use property wrapper projection argument; "
5492+
"pass wrapped value type %0 instead", (Type))
54935493
ERROR(property_wrapper_param_mutating,none,
54945494
"property wrapper applied to parameter must have a nonmutating "
54955495
"'wrappedValue' getter", ())

lib/Sema/CSDiagnostics.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3291,6 +3291,13 @@ bool MissingPropertyWrapperUnwrapFailure::diagnoseAsError() {
32913291
return true;
32923292
}
32933293

3294+
if (isa<ParamDecl>(getProperty())) {
3295+
auto wrapperType = getToType();
3296+
auto wrappedValueType = computeWrappedValueType(getProperty(), wrapperType);
3297+
emitDiagnostic(diag::property_wrapper_param_projection_invalid, wrappedValueType);
3298+
return true;
3299+
}
3300+
32943301
emitDiagnostic(diag::incorrect_property_wrapper_reference, getPropertyName(),
32953302
getFromType(), getToType(), true)
32963303
.fixItRemoveChars(getLoc(), endLoc);

lib/Sema/CSGen.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4070,23 +4070,34 @@ ConstraintSystem::applyPropertyWrapperParameter(
40704070

40714071
PropertyWrapperInitKind initKind;
40724072
if (argLabel.hasDollarPrefix()) {
4073-
auto typeInfo = param->getAttachedPropertyWrapperTypeInfo(0);
4074-
if (!typeInfo.projectedValueVar) {
4073+
auto attemptProjectedValueFix = [&](ConstraintFix *fix) -> ConstraintSystem::TypeMatchResult {
40754074
if (shouldAttemptFixes()) {
40764075
if (paramType->hasTypeVariable())
40774076
recordPotentialHole(paramType);
40784077

4079-
auto *fix = AddProjectedValue::create(*this, wrapperType, getConstraintLocator(locator));
40804078
if (!recordFix(fix))
40814079
return getTypeMatchSuccess();
40824080
}
40834081

40844082
return getTypeMatchFailure(locator);
4083+
};
4084+
4085+
auto typeInfo = param->getAttachedPropertyWrapperTypeInfo(0);
4086+
if (!typeInfo.projectedValueVar) {
4087+
auto *fix = AddProjectedValue::create(*this, wrapperType, getConstraintLocator(locator));
4088+
return attemptProjectedValueFix(fix);
40854089
}
40864090

40874091
auto projectionType = wrapperType->getTypeOfMember(param->getModuleContext(),
40884092
typeInfo.projectedValueVar);
40894093
addConstraint(matchKind, paramType, projectionType, locator);
4094+
4095+
if (param->getAttachedPropertyWrappers().front()->getArg()) {
4096+
auto *fix = UseWrappedValue::create(*this, param, /*base=*/Type(), wrapperType,
4097+
getConstraintLocator(locator));
4098+
return attemptProjectedValueFix(fix);
4099+
}
4100+
40904101
initKind = PropertyWrapperInitKind::ProjectedValue;
40914102
} else {
40924103
generateWrappedPropertyTypeConstraints(*this, wrapperType, param, paramType);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2995,12 +2995,6 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
29952995
return;
29962996
}
29972997

2998-
if (isa<ParamDecl>(D) && attr->getArg()) {
2999-
diagnose(attr->getArg()->getLoc(), diag::property_wrapper_param_arg);
3000-
attr->setInvalid();
3001-
return;
3002-
}
3003-
30042998
return;
30052999
}
30063000

test/Sema/property_wrapper_parameter_invalid.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,30 @@ func testNoProjection(message: String) {
4141
// expected-error@+1 {{cannot use property wrapper projection parameter; wrapper 'NoProjection<String>' does not have a 'projectedValue'}}
4242
takesNoProjectionWrapper($value: message)
4343
}
44+
45+
struct Projection<T> {
46+
var value: T
47+
}
48+
49+
@propertyWrapper
50+
struct Wrapper<T> {
51+
init(wrappedValue: T) {
52+
self.wrappedValue = wrappedValue
53+
}
54+
55+
init(projectedValue: Projection<T>) {
56+
self.wrappedValue = projectedValue.value
57+
}
58+
59+
var wrappedValue: T
60+
var projectedValue: Projection<T> { Projection(value: wrappedValue) }
61+
}
62+
63+
func hasWrapperAttributeArg<T>(@Wrapper() value: T) {}
64+
65+
func testWrapperAttributeArg(projection: Projection<Int>) {
66+
hasWrapperAttributeArg(value: projection.value)
67+
68+
// expected-error@+1 {{cannot use property wrapper projection argument; pass wrapped value type 'Int' instead}}
69+
hasWrapperAttributeArg($value: projection)
70+
}

0 commit comments

Comments
 (0)