Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -4329,6 +4329,19 @@ class ConstraintSystem {
llvm::function_ref<ConstraintFix *(unsigned, const OverloadChoice &)>
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.
///
Expand Down
43 changes: 18 additions & 25 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand All @@ -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<OpaqueTypeArchetypeType>()) {
// Add a conversion constraint between the types.
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -4158,7 +4150,8 @@ ConstraintSystem::applyPropertyWrapperToParameter(

initKind = PropertyWrapperInitKind::ProjectedValue;
} else {
generateWrappedPropertyTypeConstraints(*this, wrapperType, param, paramType);
Type wrappedValueType = computeWrappedValueType(param, wrapperType);
addConstraint(matchKind, paramType, wrappedValueType, locator);
initKind = PropertyWrapperInitKind::WrappedValue;
}

Expand Down
5 changes: 5 additions & 0 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
7 changes: 6 additions & 1 deletion test/Sema/property_wrapper_parameter_invalid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ struct S {
subscript(@Wrapper position: Int) -> Int { 0 }
}

func testInvalidArgLabel() {
func testInvalidArgLabel(projection: Projection<Int>) {
// expected-note@+1 2 {{parameter 'argLabel' does not have an attached property wrapper}}
func noWrappers(argLabel: Int) {}

Expand All @@ -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<Int>' to expected argument type 'Int'}}
takesWrapper(argLabel: projection)
}

protocol P {
Expand Down