Skip to content

Commit fb1a130

Browse files
committed
[SE-0258] Infer generic arguments of wrapper type from original property type
Implement the revised type inference rules that allow the type checker to infer the generic arguments of a wrapper type from the original property type, including in various structural positions. Fixes rdar://problem/51266744. (cherry picked from commit 7fca845)
1 parent e5aafaa commit fb1a130

File tree

3 files changed

+66
-40
lines changed

3 files changed

+66
-40
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4374,6 +4374,8 @@ ERROR(property_wrapper_type_requirement_not_accessible,none,
43744374
ERROR(property_wrapper_attribute_not_on_property, none,
43754375
"property wrapper attribute %0 can only be applied to a property",
43764376
(DeclName))
4377+
NOTE(property_wrapper_declared_here,none,
4378+
"property wrapper type %0 declared here", (DeclName))
43774379

43784380
ERROR(property_wrapper_multiple,none,
43794381
"only one property wrapper can be attached to a given property", ())
@@ -4413,9 +4415,9 @@ NOTE(property_wrapper_direct_init,none,
44134415
"initialize the property wrapper type directly with "
44144416
"'(...') on the attribute", ())
44154417

4416-
ERROR(property_wrapper_incompatible_unbound, none,
4417-
"property wrapper type %0 must either specify all generic arguments "
4418-
"or require only a single generic argument", (Type))
4418+
ERROR(property_wrapper_incompatible_property, none,
4419+
"property type %0 does not match that of the 'value' property of "
4420+
"its wrapper type %1", (Type, Type))
44194421

44204422
ERROR(property_wrapper_type_access,none,
44214423
"%select{%select{variable|constant}0|property}1 "

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// This file implements semantic analysis for property wrappers.
1414
//
1515
//===----------------------------------------------------------------------===//
16+
#include "ConstraintSystem.h"
1617
#include "TypeChecker.h"
1718
#include "TypeCheckType.h"
1819
#include "swift/AST/ASTContext.h"
@@ -423,43 +424,39 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate(
423424
return type;
424425
}
425426

426-
// Compose the type of property wrapper with the type of the property.
427-
428-
// We expect an unbound generic type here that refers to a single-parameter
429-
// generic type.
430-
auto wrapperAttr = var->getAttachedPropertyWrapper();
431-
auto nominal = rawType->getAnyNominal();
432-
auto unboundGeneric = rawType->getAs<UnboundGenericType>();
433-
if (!unboundGeneric ||
434-
unboundGeneric->getDecl() != nominal ||
435-
!nominal->getGenericParams() ||
436-
nominal->getGenericParams()->size() != 1) {
437-
ctx.Diags.diagnose(wrapperAttr->getLocation(),
438-
diag::property_wrapper_incompatible_unbound,
439-
rawType)
440-
.highlight(wrapperAttr->getTypeLoc().getSourceRange());
427+
// Get information about the wrapper type itself.
428+
auto wrapperInfo = var->getAttachedPropertyWrapperTypeInfo();
429+
if (!wrapperInfo)
441430
return Type();
442-
}
443431

444432
// Compute the type of the property to plug in to the wrapper type.
445433
tc.validateDecl(var);
446434
Type propertyType = var->getType();
435+
if (!propertyType || propertyType->hasError())
436+
return Type();
447437

448-
// Form the specialized type.
449-
Type wrapperType = tc.applyUnboundGenericArguments(
450-
unboundGeneric, nominal, wrapperAttr->getLocation(),
451-
TypeResolution::forContextual(var->getDeclContext()), { propertyType });
452-
453-
// Make sure no unbound types remain; this could happen if there are outer
454-
// unbound types that weren't resolved by the application of the property
455-
// type.
456-
if (wrapperType->hasUnboundGenericType()) {
457-
ctx.Diags.diagnose(wrapperAttr->getLocation(),
458-
diag::property_wrapper_incompatible_unbound,
459-
wrapperType)
460-
.highlight(wrapperAttr->getTypeLoc().getSourceRange());
438+
using namespace constraints;
439+
auto dc = var->getInnermostDeclContext();
440+
ConstraintSystem cs(tc, dc, None);
441+
auto emptyLocator = cs.getConstraintLocator(nullptr);
442+
Type openedWrapperType =
443+
cs.openUnboundGenericType(rawType, emptyLocator);
444+
Type valueMemberType = openedWrapperType->getTypeOfMember(
445+
dc->getParentModule(), wrapperInfo.valueVar);
446+
cs.addConstraint(ConstraintKind::Equal, valueMemberType,
447+
propertyType, emptyLocator);
448+
449+
SmallVector<Solution, 4> solutions;
450+
if (cs.solve(nullptr, solutions) || solutions.size() != 1) {
451+
var->diagnose(diag::property_wrapper_incompatible_property,
452+
propertyType, rawType);
453+
if (auto nominalWrapper = rawType->getAnyNominal()) {
454+
nominalWrapper->diagnose(diag::property_wrapper_declared_here,
455+
nominalWrapper->getFullName());
456+
}
461457
return Type();
462458
}
463459

460+
Type wrapperType = solutions.front().simplifyType(openedWrapperType);
464461
return wrapperType->mapTypeOutOfContext();
465462
}

test/decl/var/property_wrappers.swift

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ struct IntWrapper {
241241
}
242242

243243
@_propertyWrapper
244-
struct WrapperForHashable<T: Hashable> {
244+
struct WrapperForHashable<T: Hashable> { // expected-note{{property wrapper type 'WrapperForHashable' declared here}}
245245
var value: T
246246
}
247247

@@ -256,35 +256,62 @@ struct UseWrappersWithDifferentForm {
256256
@IntWrapper
257257
var x: Int
258258

259-
@WrapperForHashable // expected-error{{type 'NotHashable' does not conform to protocol 'Hashable'}}
260-
var y: NotHashable
259+
// FIXME: Diagnostic should be better here
260+
@WrapperForHashable
261+
var y: NotHashable // expected-error{{property type 'NotHashable' does not match that of the 'value' property of its wrapper type 'WrapperForHashable'}}
261262

262263
@WrapperForHashable
263264
var yOkay: Int
264265

265-
@WrapperWithTwoParams // expected-error{{property wrapper type 'WrapperWithTwoParams' must either specify all generic arguments or require only a single generic argument}}
266-
var z: Int
266+
@WrapperWithTwoParams
267+
var zOkay: (Int, Float)
267268

268-
@HasNestedWrapper.NestedWrapper // expected-error{{property wrapper type 'HasNestedWrapper.NestedWrapper<Int>' must either specify all generic arguments or require only a single generic argument}}
269-
var w: Int
269+
// FIXME: Need a better diagnostic here
270+
@HasNestedWrapper.NestedWrapper
271+
var w: Int // expected-error{{property type 'Int' does not match that of the 'value' property of its wrapper type 'HasNestedWrapper.NestedWrapper'}}
270272

271273
@HasNestedWrapper<Double>.NestedWrapper
272274
var wOkay: Int
275+
276+
@HasNestedWrapper.ConcreteNestedWrapper
277+
var wOkay2: Int
278+
}
279+
280+
@_propertyWrapper
281+
struct Function<T, U> { // expected-note{{property wrapper type 'Function' declared here}}
282+
var value: (T) -> U?
273283
}
274284

285+
struct TestFunction {
286+
@Function var f: (Int) -> Float?
287+
288+
@Function var f2: (Int) -> Float // expected-error{{property type '(Int) -> Float' does not match that of the 'value' property of its wrapper type 'Function'}}
289+
290+
func test() {
291+
let _: Int = $f // expected-error{{cannot convert value of type 'Function<Int, Float>' to specified type 'Int'}}
292+
}
293+
}
275294

276295
// ---------------------------------------------------------------------------
277296
// Nested wrappers
278297
// ---------------------------------------------------------------------------
279298
struct HasNestedWrapper<T> {
280299
@_propertyWrapper
281-
struct NestedWrapper<U> {
300+
struct NestedWrapper<U> { // expected-note{{property wrapper type 'NestedWrapper' declared here}}
282301
var value: U
283302
init(initialValue: U) {
284303
self.value = initialValue
285304
}
286305
}
287306

307+
@_propertyWrapper
308+
struct ConcreteNestedWrapper {
309+
var value: T
310+
init(initialValue: T) {
311+
self.value = initialValue
312+
}
313+
}
314+
288315
@NestedWrapper
289316
var y: [T] = []
290317
}

0 commit comments

Comments
 (0)