Skip to content

Commit bd03c47

Browse files
authored
Merge pull request swiftlang#33025 from hborla/repair-via-unwrap-typevar
[Property Wrappers] Fix property wrapper initialization type checking when `wrappedValue` is an optional of a generic parameter.
2 parents 95c8391 + 12fcb6d commit bd03c47

File tree

3 files changed

+41
-28
lines changed

3 files changed

+41
-28
lines changed

lib/Sema/CSGen.cpp

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3881,8 +3881,9 @@ static Expr *generateConstraintsFor(ConstraintSystem &cs, Expr *expr,
38813881
/// initializes the underlying storage variable.
38823882
/// \param wrappedVar The property that has a property wrapper.
38833883
/// \returns the type of the property.
3884-
static Type generateWrappedPropertyTypeConstraints(
3885-
ConstraintSystem &cs, Type initializerType, VarDecl *wrappedVar) {
3884+
static bool generateWrappedPropertyTypeConstraints(
3885+
ConstraintSystem &cs, Type initializerType, VarDecl *wrappedVar,
3886+
Type propertyType) {
38863887
auto dc = wrappedVar->getInnermostDeclContext();
38873888

38883889
Type wrapperType = LValueType::get(initializerType);
@@ -3896,7 +3897,7 @@ static Type generateWrappedPropertyTypeConstraints(
38963897
Type rawWrapperType = wrappedVar->getAttachedPropertyWrapperType(i);
38973898
auto wrapperInfo = wrappedVar->getAttachedPropertyWrapperTypeInfo(i);
38983899
if (rawWrapperType->hasError() || !wrapperInfo)
3899-
return Type();
3900+
return true;
39003901

39013902
// The former wrappedValue type must be equal to the current wrapper type
39023903
if (wrappedValueType) {
@@ -3914,12 +3915,12 @@ static Type generateWrappedPropertyTypeConstraints(
39143915
dc->getParentModule(), wrapperInfo.valueVar);
39153916
}
39163917

3917-
// Set up an equality constraint to drop the lvalue-ness of the value
3918-
// type we produced.
3919-
auto locator = cs.getConstraintLocator(wrappedVar);
3920-
Type propertyType = cs.createTypeVariable(locator, 0);
3921-
cs.addConstraint(ConstraintKind::Equal, propertyType, wrappedValueType, locator);
3922-
return propertyType;
3918+
// The property type must be equal to the wrapped value type
3919+
cs.addConstraint(ConstraintKind::Equal, propertyType, wrappedValueType,
3920+
cs.getConstraintLocator(wrappedVar, LocatorPathElt::ContextualType()));
3921+
cs.setContextualType(wrappedVar, TypeLoc::withoutLoc(wrappedValueType),
3922+
CTP_WrappedProperty);
3923+
return false;
39233924
}
39243925

39253926
/// Generate additional constraints for the pattern of an initialization.
@@ -3936,17 +3937,11 @@ static bool generateInitPatternConstraints(
39363937
if (!patternType)
39373938
return true;
39383939

3939-
if (auto wrappedVar = target.getInitializationWrappedVar()) {
3940-
Type propertyType = generateWrappedPropertyTypeConstraints(
3941-
cs, cs.getType(target.getAsExpr()), wrappedVar);
3942-
if (!propertyType)
3943-
return true;
3940+
if (auto wrappedVar = target.getInitializationWrappedVar())
3941+
return generateWrappedPropertyTypeConstraints(
3942+
cs, cs.getType(target.getAsExpr()), wrappedVar, patternType);
39443943

3945-
// Add an equal constraint between the pattern type and the
3946-
// property wrapper's "value" type.
3947-
cs.addConstraint(ConstraintKind::Equal, patternType,
3948-
propertyType, locator, /*isFavored*/ true);
3949-
} else if (!patternType->is<OpaqueTypeArchetypeType>()) {
3944+
if (!patternType->is<OpaqueTypeArchetypeType>()) {
39503945
// Add a conversion constraint between the types.
39513946
cs.addConstraint(ConstraintKind::Conversion, cs.getType(target.getAsExpr()),
39523947
patternType, locator, /*isFavored*/true);
@@ -4190,17 +4185,12 @@ bool ConstraintSystem::generateConstraints(
41904185
getConstraintLocator(typeRepr));
41914186
setType(typeRepr, backingType);
41924187

4193-
auto wrappedValueType =
4194-
generateWrappedPropertyTypeConstraints(*this, backingType, wrappedVar);
4195-
Type propertyType = wrappedVar->getType();
4196-
if (!wrappedValueType || propertyType->hasError())
4188+
auto propertyType = wrappedVar->getType();
4189+
if (propertyType->hasError())
41974190
return true;
41984191

4199-
addConstraint(ConstraintKind::Equal, propertyType, wrappedValueType,
4200-
getConstraintLocator(wrappedVar, LocatorPathElt::ContextualType()));
4201-
setContextualType(wrappedVar, TypeLoc::withoutLoc(wrappedValueType),
4202-
CTP_WrappedProperty);
4203-
return false;
4192+
return generateWrappedPropertyTypeConstraints(
4193+
*this, backingType, wrappedVar, propertyType);
42044194
}
42054195
}
42064196
}

lib/Sema/CSSimplify.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,6 +2958,19 @@ repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
29582958
std::tie(fromObjectType, fromUnwraps) = getObjectTypeAndUnwraps(fromType);
29592959
std::tie(toObjectType, toUnwraps) = getObjectTypeAndUnwraps(toType);
29602960

2961+
// Since equality is symmetric and it decays into a `Bind`, eagerly
2962+
// unwrapping optionals from either side might be incorrect since
2963+
// there is not enough information about what is expected e.g.
2964+
// `Int?? equal T0?` just like `T0? equal Int??` allows `T0` to be
2965+
// bound to `Int?` and there is no need to unwrap. Solver has to wait
2966+
// until more information becomes available about what `T0` is expected
2967+
// to be before taking action.
2968+
if (matchKind == ConstraintKind::Equal &&
2969+
(fromObjectType->is<TypeVariableType>() ||
2970+
toObjectType->is<TypeVariableType>())) {
2971+
return false;
2972+
}
2973+
29612974
// If `from` is not less optional than `to`, force unwrap is
29622975
// not going to help here. In case of object type of `from`
29632976
// is a type variable, let's assume that it might be optional.

test/decl/var/property_wrappers.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,3 +2021,13 @@ public struct NonVisibleImplicitInit {
20212021
return false
20222022
}
20232023
}
2024+
2025+
@propertyWrapper
2026+
struct OptionalWrapper<T> {
2027+
init() {}
2028+
var wrappedValue: T? { nil }
2029+
}
2030+
2031+
struct UseOptionalWrapper {
2032+
@OptionalWrapper var p: Int?? // Okay
2033+
}

0 commit comments

Comments
 (0)