Skip to content

Commit 2386374

Browse files
committed
[Property Wrappers] Type check out-of-line initialized property wrappers
via SolutionApplicationTarget. This allows fixes to be applied and diagnosed for better error messages in the case of failures, and removes code duplication for generating property wrapper constraints.
1 parent 142e9f6 commit 2386374

File tree

2 files changed

+29
-77
lines changed

2 files changed

+29
-77
lines changed

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 13 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -592,72 +592,23 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate(
592592
(void)var->getInterfaceType();
593593
if (!binding->isInitializerChecked(index))
594594
TypeChecker::typeCheckPatternBinding(binding, index);
595-
596-
ASTContext &ctx = var->getASTContext();
597-
Type type = ctx.getSideCachedPropertyWrapperBackingPropertyType(var);
598-
assert(type || ctx.Diags.hadAnyError());
599-
return type;
600-
}
601-
602-
// Compute the type of the property to plug in to the wrapper type.
603-
Type propertyType = var->getType();
604-
if (propertyType->hasError())
605-
return Type();
606-
607-
using namespace constraints;
608-
auto dc = var->getInnermostDeclContext();
609-
ConstraintSystem cs(dc, None);
610-
auto emptyLocator = cs.getConstraintLocator({});
611-
612-
auto wrapperAttrs = var->getAttachedPropertyWrappers();
613-
Type valueMemberType;
614-
Type outermostOpenedWrapperType;
615-
for (unsigned i : indices(wrapperAttrs)) {
616-
Type rawWrapperType = var->getAttachedPropertyWrapperType(i);
617-
if (!rawWrapperType)
595+
} else {
596+
using namespace constraints;
597+
auto dc = var->getInnermostDeclContext();
598+
ConstraintSystem cs(dc, ConstraintSystemFlags::AllowFixes);
599+
auto target = SolutionApplicationTarget::forUninitializedWrappedVar(var);
600+
auto solutions = cs.solve(target, FreeTypeVariableBinding::Disallow);
601+
602+
if (!solutions || !cs.applySolution(solutions->front(), target)) {
603+
var->setInvalid();
618604
return Type();
619-
620-
// Open the type.
621-
Type openedWrapperType =
622-
cs.openUnboundGenericTypes(rawWrapperType, emptyLocator);
623-
if (!outermostOpenedWrapperType)
624-
outermostOpenedWrapperType = openedWrapperType;
625-
626-
// If we already have a value member type, it must be equivalent to
627-
// this opened wrapper type.
628-
if (valueMemberType) {
629-
cs.addConstraint(ConstraintKind::Equal, valueMemberType,
630-
openedWrapperType, emptyLocator);
631605
}
632-
633-
// Retrieve the type of the wrapped value.
634-
auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo(i);
635-
if (!wrapperInfo)
636-
return Type();
637-
638-
valueMemberType = openedWrapperType->getTypeOfMember(
639-
dc->getParentModule(), wrapperInfo.valueVar);
640-
}
641-
642-
// The resulting value member type must be equivalent to the property
643-
// type.
644-
cs.addConstraint(ConstraintKind::Equal, valueMemberType,
645-
propertyType, emptyLocator);
646-
647-
SmallVector<Solution, 4> solutions;
648-
if (cs.solve(solutions) || solutions.size() != 1) {
649-
var->diagnose(diag::property_wrapper_incompatible_property,
650-
propertyType, rawType);
651-
var->setInvalid();
652-
if (auto nominalWrapper = rawType->getAnyNominal()) {
653-
nominalWrapper->diagnose(diag::property_wrapper_declared_here,
654-
nominalWrapper->getName());
655-
}
656-
return Type();
657606
}
658607

659-
Type wrapperType = solutions.front().simplifyType(outermostOpenedWrapperType);
660-
return wrapperType->mapTypeOutOfContext();
608+
ASTContext &ctx = var->getASTContext();
609+
Type type = ctx.getSideCachedPropertyWrapperBackingPropertyType(var);
610+
assert(type || ctx.Diags.hadAnyError());
611+
return type;
661612
}
662613

663614
Type swift::computeWrappedValueType(VarDecl *var, Type backingStorageType,

test/decl/var/property_wrappers.swift

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ struct IntWrapper {
304304
}
305305

306306
@propertyWrapper
307-
struct WrapperForHashable<T: Hashable> { // expected-note{{property wrapper type 'WrapperForHashable' declared here}}
307+
struct WrapperForHashable<T: Hashable> { // expected-note{{where 'T' = 'NotHashable'}}
308308
var wrappedValue: T
309309
}
310310

@@ -319,19 +319,17 @@ struct UseWrappersWithDifferentForm {
319319
@IntWrapper
320320
var x: Int
321321

322-
// FIXME: Diagnostic should be better here
323-
@WrapperForHashable
324-
var y: NotHashable // expected-error{{property type 'NotHashable' does not match that of the 'wrappedValue' property of its wrapper type 'WrapperForHashable'}}
322+
@WrapperForHashable // expected-error {{generic struct 'WrapperForHashable' requires that 'NotHashable' conform to 'Hashable'}}
323+
var y: NotHashable
325324

326325
@WrapperForHashable
327326
var yOkay: Int
328327

329328
@WrapperWithTwoParams
330329
var zOkay: (Int, Float)
331330

332-
// FIXME: Need a better diagnostic here
333-
@HasNestedWrapper.NestedWrapper
334-
var w: Int // expected-error{{property type 'Int' does not match that of the 'wrappedValue' property of its wrapper type 'HasNestedWrapper.NestedWrapper'}}
331+
@HasNestedWrapper.NestedWrapper // expected-error {{generic parameter 'T' could not be inferred}} expected-note {{explicitly specify}}
332+
var w: Int
335333

336334
@HasNestedWrapper<Double>.NestedWrapper
337335
var wOkay: Int
@@ -341,14 +339,16 @@ struct UseWrappersWithDifferentForm {
341339
}
342340

343341
@propertyWrapper
344-
struct Function<T, U> { // expected-note{{property wrapper type 'Function' declared here}}
342+
struct Function<T, U> { // expected-note{{'U' declared as parameter to type 'Function'}}
345343
var wrappedValue: (T) -> U?
346344
}
347345

348346
struct TestFunction {
349347
@Function var f: (Int) -> Float?
350-
351-
@Function var f2: (Int) -> Float // expected-error{{property type '(Int) -> Float' does not match that of the 'wrappedValue' property of its wrapper type 'Function'}}
348+
349+
// FIXME: This diagnostic should be more specific
350+
@Function var f2: (Int) -> Float // expected-error{{generic parameter 'U' could not be inferred}}
351+
// expected-note@-1 {{explicitly specify}}
352352

353353
func test() {
354354
let _: Int = _f // expected-error{{cannot convert value of type 'Function<Int, Float>' to specified type 'Int'}}
@@ -358,9 +358,9 @@ struct TestFunction {
358358
// ---------------------------------------------------------------------------
359359
// Nested wrappers
360360
// ---------------------------------------------------------------------------
361-
struct HasNestedWrapper<T> {
361+
struct HasNestedWrapper<T> { // expected-note {{'T' declared as parameter to type 'HasNestedWrapper'}}
362362
@propertyWrapper
363-
struct NestedWrapper<U> { // expected-note{{property wrapper type 'NestedWrapper' declared here}}
363+
struct NestedWrapper<U> {
364364
var wrappedValue: U
365365
init(wrappedValue initialValue: U) {
366366
self.wrappedValue = initialValue
@@ -1026,7 +1026,7 @@ struct WrapperB<Value> {
10261026
}
10271027

10281028
@propertyWrapper
1029-
struct WrapperC<Value> {
1029+
struct WrapperC<Value> { // expected-note {{'Value' declared as parameter to type 'WrapperC'}}
10301030
var wrappedValue: Value?
10311031

10321032
init(wrappedValue initialValue: Value?) {
@@ -1035,7 +1035,7 @@ struct WrapperC<Value> {
10351035
}
10361036

10371037
@propertyWrapper
1038-
struct WrapperD<Value, X, Y> { // expected-note{{property wrapper type 'WrapperD' declared here}}
1038+
struct WrapperD<Value, X, Y> {
10391039
var wrappedValue: Value
10401040
}
10411041

@@ -1049,7 +1049,8 @@ struct TestComposition {
10491049
@WrapperA @WrapperB @WrapperC var p2 = "Hello"
10501050
@WrapperD<WrapperE, Int, String> @WrapperE var p3: Int?
10511051
@WrapperD<WrapperC, Int, String> @WrapperC var p4: Int?
1052-
@WrapperD<WrapperC, Int, String> @WrapperE var p5: Int // expected-error{{property type 'Int' does not match that of the 'wrappedValue' property of its wrapper type 'WrapperD<WrapperC, Int, String>'}}
1052+
@WrapperD<WrapperC, Int, String> @WrapperE var p5: Int // expected-error{{generic parameter 'Value' could not be inferred}}
1053+
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}}
10531054

10541055
func triggerErrors(d: Double) { // expected-note 6 {{mark method 'mutating' to make 'self' mutable}} {{2-2=mutating }}
10551056
p1 = d // expected-error{{cannot assign value of type 'Double' to type 'Int'}} {{8-8=Int(}} {{9-9=)}}

0 commit comments

Comments
 (0)