Skip to content

Commit 133dec0

Browse files
committed
[ConstraintSystem] Implement implicit property wrapper attribute
inference for closure parameters.
1 parent 96f4315 commit 133dec0

File tree

11 files changed

+149
-44
lines changed

11 files changed

+149
-44
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5496,6 +5496,9 @@ ERROR(property_wrapper_param_projection_invalid,none,
54965496
ERROR(property_wrapper_param_mutating,none,
54975497
"property wrapper applied to parameter must have a nonmutating "
54985498
"'wrappedValue' getter", ())
5499+
ERROR(invalid_implicit_property_wrapper,none,
5500+
"inferred projection type %0 is not a property wrapper",
5501+
(Type))
54995502

55005503
ERROR(property_wrapper_mutating_get_composed_to_get_only,none,
55015504
"property wrapper %0 with a mutating getter cannot be composed inside "

include/swift/Sema/CSFix.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ enum class FixKind : uint8_t {
123123
/// a projection argument.
124124
AddProjectedValue,
125125

126+
/// Add '@propertyWrapper' to a nominal type declaration.
127+
AddPropertyWrapperAttribute,
128+
126129
/// Instead of spelling out `subscript` directly, use subscript operator.
127130
UseSubscriptOperator,
128131

@@ -966,7 +969,7 @@ class AddProjectedValue final : public ConstraintFix {
966969

967970
AddProjectedValue(ConstraintSystem &cs, Type wrapper,
968971
ConstraintLocator *locator)
969-
: ConstraintFix(cs, FixKind::UseWrappedValue, locator), wrapperType(wrapper) {}
972+
: ConstraintFix(cs, FixKind::AddProjectedValue, locator), wrapperType(wrapper) {}
970973

971974
public:
972975
static AddProjectedValue *create(ConstraintSystem &cs, Type wrapper,
@@ -979,6 +982,24 @@ class AddProjectedValue final : public ConstraintFix {
979982
bool diagnose(const Solution &solution, bool asNote = false) const override;
980983
};
981984

985+
class AddPropertyWrapperAttribute final : public ConstraintFix {
986+
Type wrapperType;
987+
988+
AddPropertyWrapperAttribute(ConstraintSystem &cs, Type wrapper,
989+
ConstraintLocator *locator)
990+
: ConstraintFix(cs, FixKind::AddPropertyWrapperAttribute, locator), wrapperType(wrapper) {}
991+
992+
public:
993+
static AddPropertyWrapperAttribute *create(ConstraintSystem &cs, Type wrapper,
994+
ConstraintLocator *locator);
995+
996+
std::string getName() const override {
997+
return "add '@propertyWrapper'";
998+
}
999+
1000+
bool diagnose(const Solution &solution, bool asNote = false) const override;
1001+
};
1002+
9821003
class UseSubscriptOperator final : public ConstraintFix {
9831004
UseSubscriptOperator(ConstraintSystem &cs, ConstraintLocator *locator)
9841005
: ConstraintFix(cs, FixKind::UseSubscriptOperator, locator) {}

lib/Sema/CSApply.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7831,23 +7831,23 @@ namespace {
78317831
if (!param->hasAttachedPropertyWrapper())
78327832
continue;
78337833

7834-
auto wrapperInfo = param->getPropertyWrapperBackingPropertyInfo();
7835-
auto *backingVar = wrapperInfo.backingVar;
7836-
auto wrapperType = solution.simplifyType(solution.getType(backingVar));
7837-
backingVar->setInterfaceType(wrapperType->mapTypeOutOfContext());
7838-
7839-
if (auto *projection = wrapperInfo.projectionVar) {
7840-
auto typeInfo = param->getAttachedPropertyWrapperTypeInfo(0);
7841-
auto projectionType = wrapperType->getTypeOfMember(param->getModuleContext(),
7842-
typeInfo.projectedValueVar);
7843-
projection->setInterfaceType(projectionType);
7834+
// Set the interface type of each property wrapper synthesized var
7835+
auto *backingVar = param->getPropertyWrapperBackingProperty();
7836+
backingVar->setInterfaceType(
7837+
solution.simplifyType(solution.getType(backingVar))->mapTypeOutOfContext());
7838+
7839+
if (auto *projectionVar = param->getPropertyWrapperProjectionVar()) {
7840+
projectionVar->setInterfaceType(
7841+
solution.simplifyType(solution.getType(projectionVar)));
78447842
}
78457843

78467844
auto *wrappedValueVar = param->getPropertyWrapperWrappedValueVar();
7847-
auto wrappedValueType = computeWrappedValueType(param, wrapperType);
7848-
wrappedValueVar->setInterfaceType(wrappedValueType);
7845+
wrappedValueVar->setInterfaceType(
7846+
solution.simplifyType(solution.getType(wrappedValueVar)));
78497847
}
78507848

7849+
TypeChecker::checkParameterList(closure->getParameters(), closure);
7850+
78517851
auto &appliedWrappers = Rewriter.solution.appliedPropertyWrappers[closure];
78527852
return Rewriter.buildPropertyWrapperFnThunk(closure, closureFnType, closure,
78537853
appliedWrappers);

lib/Sema/CSDiagnostics.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3309,6 +3309,15 @@ bool MissingProjectedValueFailure::diagnoseAsError() {
33093309
return true;
33103310
}
33113311

3312+
bool MissingPropertyWrapperAttributeFailure::diagnoseAsError() {
3313+
emitDiagnostic(diag::invalid_implicit_property_wrapper, wrapperType);
3314+
3315+
// FIXME: emit a note and fix-it to add '@propertyWrapper' if the
3316+
// type is a nominal and in the same module.
3317+
3318+
return true;
3319+
}
3320+
33123321
bool SubscriptMisuseFailure::diagnoseAsError() {
33133322
auto *locator = getLocator();
33143323
auto &sourceMgr = getASTContext().SourceMgr;

lib/Sema/CSDiagnostics.h

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

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

lib/Sema/CSFix.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,17 @@ AddProjectedValue *AddProjectedValue::create(ConstraintSystem &cs, Type wrapperT
639639
return new (cs.getAllocator()) AddProjectedValue(cs, wrapperType, locator);
640640
}
641641

642+
bool AddPropertyWrapperAttribute::diagnose(const Solution &solution, bool asNote) const {
643+
MissingPropertyWrapperAttributeFailure failure(solution, wrapperType, getLocator());
644+
return failure.diagnose(asNote);
645+
}
646+
647+
AddPropertyWrapperAttribute *AddPropertyWrapperAttribute::create(ConstraintSystem &cs,
648+
Type wrapperType,
649+
ConstraintLocator *locator) {
650+
return new (cs.getAllocator()) AddPropertyWrapperAttribute(cs, wrapperType, locator);
651+
}
652+
642653
bool UseSubscriptOperator::diagnose(const Solution &solution,
643654
bool asNote) const {
644655
SubscriptMisuseFailure failure(solution, getLocator());

lib/Sema/CSGen.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2053,18 +2053,6 @@ namespace {
20532053
TVO_CanBindToInOut | TVO_CanBindToNoEscape | TVO_CanBindToHole);
20542054
}
20552055

2056-
if (auto wrapperInfo = param->getPropertyWrapperBackingPropertyInfo()) {
2057-
auto *wrapperAttr = param->getAttachedPropertyWrappers().front();
2058-
auto wrapperType = param->getAttachedPropertyWrapperType(0);
2059-
auto backingType = CS.openUnboundGenericTypes(
2060-
wrapperType, CS.getConstraintLocator(wrapperAttr->getTypeRepr()));
2061-
CS.setType(wrapperInfo.backingVar, backingType);
2062-
2063-
CS.applyPropertyWrapperParameter(backingType, externalType, param,
2064-
param->getName(), ConstraintKind::Equal,
2065-
CS.getConstraintLocator(closure));
2066-
}
2067-
20682056
closureParams.push_back(param->toFunctionParam(externalType));
20692057
}
20702058
}
@@ -4082,17 +4070,17 @@ ConstraintSystem::applyPropertyWrapperParameter(
40824070
return getTypeMatchFailure(locator);
40834071
};
40844072

4085-
auto typeInfo = param->getAttachedPropertyWrapperTypeInfo(0);
4073+
auto typeInfo = wrapperType->getAnyNominal()->getPropertyWrapperTypeInfo();
40864074
if (!typeInfo.projectedValueVar) {
40874075
auto *fix = AddProjectedValue::create(*this, wrapperType, getConstraintLocator(locator));
40884076
return attemptProjectedValueFix(fix);
40894077
}
40904078

4091-
auto projectionType = wrapperType->getTypeOfMember(param->getModuleContext(),
4092-
typeInfo.projectedValueVar);
4079+
Type projectionType = computeProjectedValueType(param, wrapperType);
40934080
addConstraint(matchKind, paramType, projectionType, locator);
40944081

4095-
if (param->getAttachedPropertyWrappers().front()->getArg()) {
4082+
if (!param->hasImplicitPropertyWrapper() &&
4083+
param->getAttachedPropertyWrappers().front()->getArg()) {
40964084
auto *fix = UseWrappedValue::create(*this, param, /*base=*/Type(), wrapperType,
40974085
getConstraintLocator(locator));
40984086
return attemptProjectedValueFix(fix);

lib/Sema/CSSimplify.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8197,6 +8197,54 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
81978197
param = param.withFlags(contextualParam->getParameterFlags());
81988198
}
81998199

8200+
if (paramDecl->hasAttachedPropertyWrapper()) {
8201+
bool hasError = false;
8202+
Type backingType;
8203+
8204+
if (paramDecl->hasImplicitPropertyWrapper()) {
8205+
backingType = getContextualParamAt(i)->getPlainType();
8206+
8207+
// If the contextual type is not a property wrapper, record a fix.
8208+
auto *nominal = backingType->getAnyNominal();
8209+
if (!(nominal && nominal->getAttrs().hasAttribute<PropertyWrapperAttr>())) {
8210+
if (!shouldAttemptFixes())
8211+
return false;
8212+
8213+
paramDecl->visitAuxiliaryDecls([](VarDecl *var) {
8214+
var->setInvalid();
8215+
});
8216+
8217+
auto *fix = AddPropertyWrapperAttribute::create(*this, backingType,
8218+
getConstraintLocator(paramDecl));
8219+
recordFix(fix);
8220+
hasError = true;
8221+
}
8222+
} else {
8223+
auto *wrapperAttr = paramDecl->getAttachedPropertyWrappers().front();
8224+
auto wrapperType = paramDecl->getAttachedPropertyWrapperType(0);
8225+
backingType = replaceInferableTypesWithTypeVars(
8226+
wrapperType, getConstraintLocator(wrapperAttr->getTypeRepr()));
8227+
}
8228+
8229+
if (!hasError) {
8230+
auto result = applyPropertyWrapperParameter(backingType, param.getParameterType(),
8231+
paramDecl, paramDecl->getName(),
8232+
ConstraintKind::Equal, locator);
8233+
if (result.isFailure())
8234+
return false;
8235+
8236+
auto *backingVar = paramDecl->getPropertyWrapperBackingProperty();
8237+
setType(backingVar, backingType);
8238+
8239+
auto *localWrappedVar = paramDecl->getPropertyWrapperWrappedValueVar();
8240+
setType(localWrappedVar, computeWrappedValueType(paramDecl, backingType));
8241+
8242+
if (auto *projection = paramDecl->getPropertyWrapperProjectionVar()) {
8243+
setType(projection, computeProjectedValueType(paramDecl, backingType));
8244+
}
8245+
}
8246+
}
8247+
82008248
Type internalType;
82018249
if (paramDecl->getTypeRepr()) {
82028250
// Internal type is the type used in the body of the closure,
@@ -10665,6 +10713,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1066510713
case FixKind::UsePropertyWrapper:
1066610714
case FixKind::UseWrappedValue:
1066710715
case FixKind::AddProjectedValue:
10716+
case FixKind::AddPropertyWrapperAttribute:
1066810717
case FixKind::ExpandArrayIntoVarargs:
1066910718
case FixKind::UseRawValue:
1067010719
case FixKind::ExplicitlyConstructRawRepresentable:

lib/Sema/TypeCheckStmt.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,13 +2081,6 @@ bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) {
20812081
TypeChecker::checkClosureAttributes(closure);
20822082
TypeChecker::checkParameterList(closure->getParameters(), closure);
20832083

2084-
for (auto *param : *closure->getParameters()) {
2085-
if (!param->isImplicit() && param->getName().hasDollarPrefix() &&
2086-
!param->hasAttachedPropertyWrapper()) {
2087-
param->diagnose(diag::dollar_identifier_decl, param->getName());
2088-
}
2089-
}
2090-
20912084
BraceStmt *body = closure->getBody();
20922085

20932086
Optional<FunctionBodyTimer> timer;

test/Parse/dollar_identifier.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,9 @@ func $declareWithDollar() { // expected-error{{cannot declare entity named '$dec
7777
$b c: Int) { } // expected-error{{cannot declare entity named '$b'}}
7878
let _: (Int) -> Int = {
7979
[$capture = 0] // expected-error{{cannot declare entity named '$capture'}}
80-
$a in // diagnosed after type checking the closure
80+
$a in // expected-error{{inferred projection type 'Int' is not a property wrapper}}
8181
$capture
8282
}
83-
let _: (Int) -> Void = {
84-
$a in // expected-error{{cannot declare entity named '$a'}}
85-
}
8683
let ($a: _, _) = (0, 0) // expected-error{{cannot declare entity named '$a'}}
8784
$label: if true { // expected-error{{cannot declare entity named '$label'}}
8885
break $label

0 commit comments

Comments
 (0)