Skip to content

Commit 358346c

Browse files
committed
[AST/Sema] TypeWrappers: Add propertyKeyPath parameter to type wrapper subscripts
The compiler is going to synthesize `\.<property-name>` as an argument to `propertyKeyPath:` parameter which points to the wrapped property.
1 parent b769f9f commit 358346c

11 files changed

+240
-185
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6614,7 +6614,7 @@ ERROR(cannot_declare_type_wrapper_init_with_invalid_second_param,none,
66146614

66156615
ERROR(type_wrapper_requires_subscript,none,
66166616
"type wrapper type %0 does not contain a required subscript"
6617-
" - subscript(storedKeyPath:)",
6617+
" - subscript(propertyKeyPath:storageKeyPath:)",
66186618
(DeclName))
66196619

66206620
ERROR(type_wrapper_requires_readonly_subscript,none,
@@ -6631,9 +6631,9 @@ NOTE(add_type_wrapper_subscript_stub_note,none,
66316631
ERROR(type_wrapper_failable_init,none,
66326632
"type wrapper initializer %0 cannot be failable", (DeclName))
66336633

6634-
ERROR(type_wrapper_invalid_subscript_param_type, none,
6635-
"type wrapper subscript expects a key path parameter type (got: %0)",
6636-
(Type))
6634+
ERROR(type_wrapper_subscript_invalid_parameter,none,
6635+
"type wrapper subscript %0 parameter expects a key path (got: %1)",
6636+
(Identifier, Type))
66376637

66386638
ERROR(type_wrapper_type_requirement_not_accessible,none,
66396639
"%select{private|fileprivate|internal|public|open}0 %1 %2 cannot have "

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ IDENTIFIER_WITH_NAME(builderSelf, "$builderSelf")
313313
IDENTIFIER_WITH_NAME(TypeWrapperStorage, "$Storage")
314314
IDENTIFIER_WITH_NAME(TypeWrapperProperty, "$storage")
315315
IDENTIFIER(storageKeyPath)
316+
IDENTIFIER(propertyKeyPath)
316317
IDENTIFIER_WITH_NAME(localStorageVar, "_storage")
317318

318319
// Attribute options

lib/Sema/TypeCheckAttr.cpp

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3732,7 +3732,12 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
37323732
std::min(nominal->getFormalAccess(), AccessLevel::Public);
37333733
};
37343734

3735-
enum class UnviabilityReason { Failable, InvalidType, Inaccessible };
3735+
enum class UnviabilityReason {
3736+
Failable,
3737+
InvalidPropertyType,
3738+
InvalidStorageType,
3739+
Inaccessible
3740+
};
37363741

37373742
auto findMembersOrDiagnose = [&](DeclName memberName,
37383743
SmallVectorImpl<ValueDecl *> &results,
@@ -3808,7 +3813,8 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
38083813
nominal->getFormalAccess());
38093814
break;
38103815

3811-
case UnviabilityReason::InvalidType:
3816+
case UnviabilityReason::InvalidStorageType:
3817+
case UnviabilityReason::InvalidPropertyType:
38123818
llvm_unreachable("init(storage:) type is not checked");
38133819
}
38143820
}
@@ -3874,11 +3880,10 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
38743880
}
38753881
}
38763882

3877-
// subscript(storedKeypath: KeyPath<...>)
3883+
// subscript(propertyKeyPath: KeyPath, storedKeypath: {Writable}KeyPath)
38783884
{
3879-
DeclName subscriptName(
3880-
ctx, DeclBaseName::createSubscript(),
3881-
ArrayRef<Identifier>(ctx.getIdentifier("storageKeyPath")));
3885+
DeclName subscriptName(ctx, DeclBaseName::createSubscript(),
3886+
{ctx.Id_propertyKeyPath, ctx.Id_storageKeyPath});
38823887

38833888
SmallVector<ValueDecl *, 2> subscripts;
38843889
if (findMembersOrDiagnose(subscriptName, subscripts,
@@ -3891,25 +3896,33 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
38913896
bool hasReadOnly = false;
38923897
bool hasWritable = false;
38933898

3899+
auto hasKeyPathType = [](ParamDecl *PD) {
3900+
if (auto *BGT = PD->getInterfaceType()->getAs<BoundGenericType>()) {
3901+
return BGT->isKeyPath() || BGT->isWritableKeyPath() ||
3902+
BGT->isReferenceWritableKeyPath();
3903+
}
3904+
return false;
3905+
};
3906+
38943907
for (auto *decl : subscripts) {
38953908
auto *subscript = cast<SubscriptDecl>(decl);
38963909

3897-
auto *keyPathParam = subscript->getIndices()->get(0);
3898-
3899-
if (auto *BGT =
3900-
keyPathParam->getInterfaceType()->getAs<BoundGenericType>()) {
3901-
if (!(BGT->isKeyPath() || BGT->isWritableKeyPath() ||
3902-
BGT->isReferenceWritableKeyPath())) {
3903-
nonViableSubscripts[subscript].push_back(
3904-
UnviabilityReason::InvalidType);
3905-
} else {
3906-
hasReadOnly |= BGT->isKeyPath();
3907-
hasWritable |=
3908-
BGT->isWritableKeyPath() || BGT->isReferenceWritableKeyPath();
3909-
}
3910+
auto *propertyKeyPathParam = subscript->getIndices()->get(0);
3911+
3912+
if (!hasKeyPathType(propertyKeyPathParam)) {
3913+
nonViableSubscripts[subscript].push_back(
3914+
UnviabilityReason::InvalidPropertyType);
3915+
}
3916+
3917+
auto *storageKeyPathParam = subscript->getIndices()->get(1);
3918+
if (hasKeyPathType(storageKeyPathParam)) {
3919+
auto type = storageKeyPathParam->getInterfaceType();
3920+
hasReadOnly |= type->isKeyPath();
3921+
hasWritable |=
3922+
type->isWritableKeyPath() || type->isReferenceWritableKeyPath();
39103923
} else {
39113924
nonViableSubscripts[subscript].push_back(
3912-
UnviabilityReason::InvalidType);
3925+
UnviabilityReason::InvalidStorageType);
39133926
}
39143927

39153928
if (isLessAccessibleThanType(subscript))
@@ -3928,7 +3941,9 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
39283941
diag::add_type_wrapper_subscript_stub_note)
39293942
.fixItInsertAfter(
39303943
nominal->getBraces().Start,
3931-
"\nsubscript<Value>(storageKeyPath path: KeyPath<<#Base#>, "
3944+
"\nsubscript<Value>(propertyKeyPath propPath: "
3945+
"KeyPath<<#WrappedType#>, Value>, storageKeyPath "
3946+
"storagePath: KeyPath<<#Base#>, "
39323947
"Value>) -> Value { get { <#code#> } }");
39333948
});
39343949
attr->setInvalid();
@@ -3945,7 +3960,9 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
39453960
diag::add_type_wrapper_subscript_stub_note)
39463961
.fixItInsertAfter(
39473962
nominal->getBraces().Start,
3948-
"\nsubscript<Value>(storageKeyPath path: "
3963+
"\nsubscript<Value>(propertyKeyPath propPath: "
3964+
"KeyPath<<#WrappedType#>, Value>, storageKeyPath "
3965+
"storagePath: "
39493966
"WritableKeyPath<<#Base#>, "
39503967
"Value>) -> Value { get { <#code#> } set { <#code#> } }");
39513968
});
@@ -3958,10 +3975,17 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
39583975

39593976
for (auto reason : entry.second) {
39603977
switch (reason) {
3961-
case UnviabilityReason::InvalidType: {
3978+
case UnviabilityReason::InvalidPropertyType: {
39623979
auto paramTy = subscript->getIndices()->get(0)->getInterfaceType();
3963-
diagnose(subscript, diag::type_wrapper_invalid_subscript_param_type,
3964-
paramTy);
3980+
diagnose(subscript, diag::type_wrapper_subscript_invalid_parameter,
3981+
ctx.Id_propertyKeyPath, paramTy);
3982+
break;
3983+
}
3984+
3985+
case UnviabilityReason::InvalidStorageType: {
3986+
auto paramTy = subscript->getIndices()->get(1)->getInterfaceType();
3987+
diagnose(subscript, diag::type_wrapper_subscript_invalid_parameter,
3988+
ctx.Id_storageKeyPath, paramTy);
39653989
break;
39663990
}
39673991

lib/Sema/TypeCheckTypeWrapper.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,21 @@ static SubscriptExpr *subscriptTypeWrappedProperty(VarDecl *var,
258258
assert(storageVar);
259259

260260
// \$Storage.<property-name>
261-
auto *argExpr = KeyPathExpr::createImplicit(
261+
auto *storageKeyPath = KeyPathExpr::createImplicit(
262262
ctx, /*backslashLoc=*/SourceLoc(),
263263
{KeyPathExpr::Component::forProperty(
264264
{storageVar},
265265
useDC->mapTypeIntoContext(storageVar->getInterfaceType()),
266266
/*Loc=*/SourceLoc())},
267267
/*endLoc=*/SourceLoc());
268268

269+
// WrappedType.<property-name>
270+
auto *propertyKeyPath = KeyPathExpr::createImplicit(
271+
ctx, /*backslashLoc=*/SourceLoc(),
272+
{KeyPathExpr::Component::forUnresolvedProperty(
273+
DeclNameRef(var->getName()), /*Loc=*/SourceLoc())},
274+
/*endLoc=*/SourceLoc());
275+
269276
auto *subscriptBaseExpr = UnresolvedDotExpr::createImplicit(
270277
ctx,
271278
new (ctx) DeclRefExpr({useDC->getImplicitSelfDecl()},
@@ -275,7 +282,11 @@ static SubscriptExpr *subscriptTypeWrappedProperty(VarDecl *var,
275282
// $storage[storageKeyPath: \$Storage.<property-name>]
276283
return SubscriptExpr::create(
277284
ctx, subscriptBaseExpr,
278-
ArgumentList::forImplicitSingle(ctx, ctx.Id_storageKeyPath, argExpr),
285+
ArgumentList::createImplicit(
286+
ctx, {Argument(/*loc=*/SourceLoc(), ctx.Id_propertyKeyPath,
287+
propertyKeyPath),
288+
Argument(/*loc=*/SourceLoc(), ctx.Id_storageKeyPath,
289+
storageKeyPath)}),
279290
ConcreteDeclRef(), /*implicit=*/true);
280291
}
281292

test/Interpreter/Inputs/type_wrapper_defs.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,23 @@ public struct Wrapper<W, S> {
77
self.underlying = storage
88
}
99

10-
public subscript<V>(storageKeyPath path: KeyPath<S, V>) -> V {
10+
public subscript<V>(propertyKeyPath propertyPath: KeyPath<W, V>,
11+
storageKeyPath storagePath: KeyPath<S, V>) -> V {
1112
get {
12-
print("in read-only getter")
13-
return underlying[keyPath: path]
13+
print("in read-only getter storage: \(storagePath), property: \(propertyPath)")
14+
return underlying[keyPath: storagePath]
1415
}
1516
}
1617

17-
public subscript<V>(storageKeyPath path: WritableKeyPath<S, V>) -> V {
18+
public subscript<V>(propertyKeyPath propertyPath: KeyPath<W, V>,
19+
storageKeyPath storagePath: WritableKeyPath<S, V>) -> V {
1820
get {
19-
print("in getter")
20-
return underlying[keyPath: path]
21+
print("in getter storage: \(storagePath), property: \(propertyPath)")
22+
return underlying[keyPath: storagePath]
2123
}
2224
set {
2325
print("in setter => \(newValue)")
24-
underlying[keyPath: path] = newValue
26+
underlying[keyPath: storagePath] = newValue
2527
}
2628
}
2729
}

test/Interpreter/type_wrapper_with_actors.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
// (rdar://99051588)
2020
// UNSUPPORTED: remote_run || device_run
2121

22+
// FIXME: There is no way to form a key path to an actor isolated property (rdar://84445219)
23+
// REQUIRES: rdar84445219
24+
2225
import type_wrapper_defs
2326

2427
@Wrapper

0 commit comments

Comments
 (0)