From 138c1170eabb8a655a1fe8f3d464a31f292087b2 Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 2 Sep 2021 07:55:24 -0700 Subject: [PATCH 1/2] [CSGen] Declare generateWrappedPropertyTypeConstraints as a method on ConstraintSystem. --- include/swift/Sema/ConstraintSystem.h | 13 +++++++++ lib/Sema/CSGen.cpp | 42 +++++++++++---------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 72cfb3981b23a..fc1b5f8b4ecf9 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -4329,6 +4329,19 @@ class ConstraintSystem { llvm::function_ref getFix = [](unsigned, const OverloadChoice &) { return nullptr; }); + /// Generate constraints for the given property that has an + /// attached property wrapper. + /// + /// \param wrappedVar The property that has a property wrapper. + /// \param initializerType The type of the initializer for the + /// backing storage variable. + /// \param propertyType The type of the wrapped property. + /// + /// \returns true if there is an error. + bool generateWrappedPropertyTypeConstraints(VarDecl *wrappedVar, + Type initializerType, + Type propertyType); + /// Propagate constraints in an effort to enforce local /// consistency to reduce the time to solve the system. /// diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 52a9ed8645c35..9e0f844e5c1d9 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -3602,16 +3602,8 @@ static Expr *generateConstraintsFor(ConstraintSystem &cs, Expr *expr, return result; } -/// Generate constraints to produce the wrapped value type given the property -/// that has an attached property wrapper. -/// -/// \param initializerType The type of the adjusted initializer, which -/// initializes the underlying storage variable. -/// \param wrappedVar The property that has a property wrapper. -/// \returns the type of the property. -static bool generateWrappedPropertyTypeConstraints( - ConstraintSystem &cs, Type initializerType, VarDecl *wrappedVar, - Type propertyType) { +bool ConstraintSystem::generateWrappedPropertyTypeConstraints( + VarDecl *wrappedVar, Type initializerType, Type propertyType) { auto dc = wrappedVar->getInnermostDeclContext(); Type wrappedValueType; @@ -3630,33 +3622,33 @@ static bool generateWrappedPropertyTypeConstraints( if (!wrappedValueType) { // Equate the outermost wrapper type to the initializer type. - auto *locator = cs.getConstraintLocator(typeExpr); + auto *locator = getConstraintLocator(typeExpr); wrapperType = - cs.replaceInferableTypesWithTypeVars(rawWrapperType, locator); + replaceInferableTypesWithTypeVars(rawWrapperType, locator); if (initializerType) - cs.addConstraint(ConstraintKind::Equal, wrapperType, initializerType, locator); + addConstraint(ConstraintKind::Equal, wrapperType, initializerType, locator); } else { // The former wrappedValue type must be equal to the current wrapper type - auto *locator = cs.getConstraintLocator( + auto *locator = getConstraintLocator( typeExpr, LocatorPathElt::WrappedValue(wrapperType)); wrapperType = - cs.replaceInferableTypesWithTypeVars(rawWrapperType, locator); - cs.addConstraint(ConstraintKind::Equal, wrapperType, wrappedValueType, locator); + replaceInferableTypesWithTypeVars(rawWrapperType, locator); + addConstraint(ConstraintKind::Equal, wrapperType, wrappedValueType, locator); } - cs.setType(typeExpr, wrapperType); + setType(typeExpr, wrapperType); wrappedValueType = wrapperType->getTypeOfMember( dc->getParentModule(), wrapperInfo.valueVar); } // The property type must be equal to the wrapped value type - cs.addConstraint( + addConstraint( ConstraintKind::Equal, propertyType, wrappedValueType, - cs.getConstraintLocator( + getConstraintLocator( wrappedVar, LocatorPathElt::ContextualType(CTP_WrappedProperty))); - cs.setContextualType(wrappedVar, TypeLoc::withoutLoc(wrappedValueType), - CTP_WrappedProperty); + setContextualType(wrappedVar, TypeLoc::withoutLoc(wrappedValueType), + CTP_WrappedProperty); return false; } @@ -3675,8 +3667,8 @@ static bool generateInitPatternConstraints( return true; if (auto wrappedVar = target.getInitializationWrappedVar()) - return generateWrappedPropertyTypeConstraints( - cs, cs.getType(target.getAsExpr()), wrappedVar, patternType); + return cs.generateWrappedPropertyTypeConstraints( + wrappedVar, cs.getType(target.getAsExpr()), patternType); if (!patternType->is()) { // Add a conversion constraint between the types. @@ -3968,7 +3960,7 @@ bool ConstraintSystem::generateConstraints( return true; return generateWrappedPropertyTypeConstraints( - *this, /*initializerType=*/Type(), wrappedVar, propertyType); + wrappedVar, /*initializerType=*/Type(), propertyType); } else { auto pattern = target.getAsUninitializedVar(); auto locator = getConstraintLocator( @@ -4158,7 +4150,7 @@ ConstraintSystem::applyPropertyWrapperToParameter( initKind = PropertyWrapperInitKind::ProjectedValue; } else { - generateWrappedPropertyTypeConstraints(*this, wrapperType, param, paramType); + generateWrappedPropertyTypeConstraints(param, wrapperType, paramType); initKind = PropertyWrapperInitKind::WrappedValue; } From 947a6c32a52a4eec76277fba9faf9ac974292c3b Mon Sep 17 00:00:00 2001 From: Holly Borla Date: Thu, 2 Sep 2021 13:25:00 -0700 Subject: [PATCH 2/2] [ConstraintSystem] In the solver, only generate constraints for wrapped parameter attributes for closure parameters. For regular function parameters, these constraints will have already been generated and solved when computing the backing property wrapper type at the function declaration. If the solver also generates these constraints when type checking a function call, it leads to misleading diagnostics about an argument mismatch that will appear at the function declaration instead of the call-site. --- lib/Sema/CSGen.cpp | 3 ++- lib/Sema/CSSimplify.cpp | 5 +++++ test/Sema/property_wrapper_parameter_invalid.swift | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 9e0f844e5c1d9..bf115e9a10bd9 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -4150,7 +4150,8 @@ ConstraintSystem::applyPropertyWrapperToParameter( initKind = PropertyWrapperInitKind::ProjectedValue; } else { - generateWrappedPropertyTypeConstraints(param, wrapperType, paramType); + Type wrappedValueType = computeWrappedValueType(param, wrapperType); + addConstraint(matchKind, paramType, wrappedValueType, locator); initKind = PropertyWrapperInitKind::WrappedValue; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 98b3432b02157..c0969eb70adb8 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -8897,6 +8897,11 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar, setType(projection, computeProjectedValueType(paramDecl, backingType)); } + if (!paramDecl->getName().hasDollarPrefix()) { + generateWrappedPropertyTypeConstraints(paramDecl, backingType, + param.getParameterType()); + } + auto result = applyPropertyWrapperToParameter(backingType, param.getParameterType(), paramDecl, paramDecl->getName(), ConstraintKind::Equal, diff --git a/test/Sema/property_wrapper_parameter_invalid.swift b/test/Sema/property_wrapper_parameter_invalid.swift index 6075549e467a8..7bae8576c8785 100644 --- a/test/Sema/property_wrapper_parameter_invalid.swift +++ b/test/Sema/property_wrapper_parameter_invalid.swift @@ -86,7 +86,7 @@ struct S { subscript(@Wrapper position: Int) -> Int { 0 } } -func testInvalidArgLabel() { +func testInvalidArgLabel(projection: Projection) { // expected-note@+1 2 {{parameter 'argLabel' does not have an attached property wrapper}} func noWrappers(argLabel: Int) {} @@ -95,6 +95,11 @@ func testInvalidArgLabel() { // expected-error@+1 {{cannot use property wrapper projection argument}} noWrappers($argLabel: 10) + + func takesWrapper(@Wrapper argLabel: Int) {} + + // expected-error@+1 {{cannot convert value of type 'Projection' to expected argument type 'Int'}} + takesWrapper(argLabel: projection) } protocol P {