Skip to content

Commit 3843b78

Browse files
committed
Guard feature behind experimental flag.
1 parent e32da1c commit 3843b78

File tree

14 files changed

+98
-20
lines changed

14 files changed

+98
-20
lines changed

include/swift/Basic/Features.def

+1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ EXPERIMENTAL_FEATURE(MacrosOnImports, true)
255255
EXPERIMENTAL_FEATURE(TupleConformances, false)
256256
EXPERIMENTAL_FEATURE(FullTypedThrows, false)
257257
EXPERIMENTAL_FEATURE(SameElementRequirements, false)
258+
EXPERIMENTAL_FEATURE(KeyPathWithMethodMembers, false)
258259

259260
// Whether to enable @_used and @_section attributes
260261
EXPERIMENTAL_FEATURE(SymbolLinkageMarkers, true)

include/swift/Sema/CSFix.h

+9
Original file line numberDiff line numberDiff line change
@@ -2009,6 +2009,11 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
20092009
// a key path component.
20102010
MutatingGetter,
20112011
// Allow a reference to a mutating method.
2012+
Method,
2013+
// Allow a reference to a initializer instance as a key path
2014+
// component.
2015+
Initializer,
2016+
// Allow a reference to an enum case as a key path component.
20122017
MutatingMethod,
20132018
// Allow a reference to an async or throwing method.
20142019
AsyncOrThrowsMethod,
@@ -2035,6 +2040,10 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
20352040
case RefKind::MutatingGetter:
20362041
return "allow reference to a member with mutating getter as a key "
20372042
"path component";
2043+
case RefKind::Method:
2044+
return "allow reference to a method as a key path component";
2045+
case RefKind::Initializer:
2046+
return "allow reference to an init method as a key path component";
20382047
case RefKind::EnumCase:
20392048
return "allow reference to an enum case as a key path component";
20402049
case RefKind::MutatingMethod:

lib/AST/FeatureSet.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ UNINTERESTING_FEATURE(StructLetDestructuring)
124124
UNINTERESTING_FEATURE(MacrosOnImports)
125125
UNINTERESTING_FEATURE(AsyncCallerExecution)
126126
UNINTERESTING_FEATURE(ExtensibleEnums)
127+
UNINTERESTING_FEATURE(KeyPathWithMethodMembers)
127128

128129
static bool usesFeatureNonescapableTypes(Decl *decl) {
129130
auto containsNonEscapable =

lib/Sema/CSDiagnostics.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -6417,6 +6417,12 @@ bool InvalidMemberWithMutatingGetterInKeyPath::diagnoseAsError() {
64176417
return true;
64186418
}
64196419

6420+
bool UnsupportedMethodRefInKeyPath::diagnoseAsError() {
6421+
emitDiagnostic(diag::expr_keypath_not_property, getMember(),
6422+
isForKeyPathDynamicMemberLookup());
6423+
return true;
6424+
}
6425+
64206426
bool InvalidMutatingMethodRefInKeyPath::diagnoseAsError() {
64216427
emitDiagnostic(diag::expr_keypath_mutating_method, getMember(),
64226428
isForKeyPathDynamicMemberLookup());

lib/Sema/CSDiagnostics.h

+27
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,33 @@ class InvalidEnumCaseRefInKeyPath final : public InvalidMemberRefInKeyPath {
18071807
bool diagnoseAsError() override;
18081808
};
18091809

1810+
/// Diagnose an attempt to reference a method or initializer as a key path
1811+
/// component.
1812+
///
1813+
/// Only diagnosed if `-KeyPathWithMethodMember` feature flag is not set.
1814+
///
1815+
/// ```swift
1816+
/// struct S {
1817+
/// init() { }
1818+
/// func foo() -> Int { return 42 }
1819+
/// static func bar() -> Int { return 0 }
1820+
/// }
1821+
///
1822+
/// _ = \S.foo
1823+
/// _ = \S.Type.bar
1824+
/// _ = \S.init
1825+
/// ```
1826+
class UnsupportedMethodRefInKeyPath final : public InvalidMemberRefInKeyPath {
1827+
public:
1828+
UnsupportedMethodRefInKeyPath(const Solution &solution, ValueDecl *method,
1829+
ConstraintLocator *locator)
1830+
: InvalidMemberRefInKeyPath(solution, method, locator) {
1831+
assert(isa<FuncDecl>(method) || isa<ConstructorDecl>(method));
1832+
}
1833+
1834+
bool diagnoseAsError() override;
1835+
};
1836+
18101837
/// Diagnose an attempt to reference a mutating method as a key path component
18111838
/// e.g.
18121839
///

lib/Sema/CSFix.cpp

+35-11
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,11 @@ bool AllowInvalidRefInKeyPath::diagnose(const Solution &solution,
12511251
getLocator());
12521252
return failure.diagnose(asNote);
12531253
}
1254+
case RefKind::Method:
1255+
case RefKind::Initializer: {
1256+
UnsupportedMethodRefInKeyPath failure(solution, Member, getLocator());
1257+
return failure.diagnose(asNote);
1258+
}
12541259
case RefKind::MutatingMethod: {
12551260
InvalidMutatingMethodRefInKeyPath failure(solution, Member, getLocator());
12561261
return failure.diagnose(asNote);
@@ -1323,22 +1328,41 @@ AllowInvalidRefInKeyPath::forRef(ConstraintSystem &cs, Type baseType,
13231328
cs, baseType, RefKind::MutatingGetter, member, locator);
13241329
}
13251330

1326-
// Referencing mutating, throws or async method members is not currently
1327-
// allowed.
1328-
if (auto method = dyn_cast<FuncDecl>(member)) {
1329-
if (method->isAsyncContext())
1330-
return AllowInvalidRefInKeyPath::create(
1331-
cs, baseType, RefKind::AsyncOrThrowsMethod, member, locator);
1332-
if (auto methodType = method->getInterfaceType()->getAs<AnyFunctionType>()) {
1333-
if (methodType->getResult()->getAs<AnyFunctionType>()->isThrowing())
1331+
if (cs.getASTContext().LangOpts.hasFeature(
1332+
Feature::KeyPathWithMethodMembers)) {
1333+
// Referencing mutating, throws or async method members is not currently
1334+
// allowed.
1335+
if (auto method = dyn_cast<FuncDecl>(member)) {
1336+
if (method->isAsyncContext())
13341337
return AllowInvalidRefInKeyPath::create(
13351338
cs, baseType, RefKind::AsyncOrThrowsMethod, member, locator);
1339+
if (auto methodType =
1340+
method->getInterfaceType()->getAs<AnyFunctionType>()) {
1341+
if (methodType->getResult()->getAs<AnyFunctionType>()->isThrowing())
1342+
return AllowInvalidRefInKeyPath::create(
1343+
cs, baseType, RefKind::AsyncOrThrowsMethod, member, locator);
1344+
}
1345+
if (method->isMutating())
1346+
return AllowInvalidRefInKeyPath::create(
1347+
cs, baseType, RefKind::MutatingMethod, member, locator);
1348+
return nullptr;
13361349
}
1337-
if (method->isMutating())
1338-
return AllowInvalidRefInKeyPath::create(
1339-
cs, baseType, RefKind::MutatingMethod, member, locator);
1350+
1351+
if (isa<ConstructorDecl>(member))
1352+
return nullptr;
13401353
}
13411354

1355+
// Referencing (instance or static) methods in key path is
1356+
// not currently allowed.
1357+
if (isa<FuncDecl>(member))
1358+
return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Method,
1359+
member, locator);
1360+
1361+
// Referencing initializers in key path is not currently allowed.
1362+
if (isa<ConstructorDecl>(member))
1363+
return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Initializer,
1364+
member, locator);
1365+
13421366
return nullptr;
13431367
}
13441368

lib/Sema/CSSimplify.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -10797,6 +10797,9 @@ static ConstraintFix *validateInitializerRef(ConstraintSystem &cs,
1079710797
// which means MetatypeType has to be added after finding a type variable.
1079810798
if (baseLocator->isLastElement<LocatorPathElt::MemberRefBase>())
1079910799
baseType = MetatypeType::get(baseType);
10800+
} else if (auto *keyPathExpr = getAsExpr<KeyPathExpr>(anchor)) {
10801+
// Key path can't refer to initializers e.g. `\Type.init`
10802+
return AllowInvalidRefInKeyPath::forRef(cs, baseType, init, locator);
1080010803
}
1080110804

1080210805
if (!baseType)

test/Constraints/keypath.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-swift-frontend -typecheck -verify %S/Inputs/keypath.swift -primary-file %s
1+
// RUN: %target-swift-frontend -enable-experimental-feature KeyPathWithMethodMembers -typecheck -verify %S/Inputs/keypath.swift -primary-file %s
2+
// REQUIRES: swift_feature_KeyPathWithMethodMembers
23

34
struct S {
45
let i: Int

test/Constraints/rdar68155466.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-feature KeyPathWithMethodMembers -typecheck -verify %s
22
// REQUIRES: objc_interop
3+
// REQUIRES: swift_feature_KeyPathWithMethodMembers
34

45
import Foundation
56

test/Interpreter/keypath.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
// RUN: %target-run-simple-swift | %FileCheck %s
1+
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-feature -Xfrontend KeyPathWithMethodMembers) | %FileCheck %s
22

33
// REQUIRES: executable_test
4+
// REQUIRES: swift_feature_KeyPathWithMethodMembers
45

56
// UNSUPPORTED: use_os_stdlib
67
// UNSUPPORTED: back_deployment_runtime

test/Interpreter/static_keypaths.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
// RUN: split-file %s %t/src
33

44
/// Build LibA
5-
// RUN: %host-build-swift %t/src/LibA.swift -swift-version 5 -emit-module -emit-library -enable-library-evolution -module-name LibA -o %t/%target-library-name(LibA) -emit-module-interface-path %t/LibA.swiftinterface
5+
// RUN: %host-build-swift %t/src/LibA.swift -swift-version 5 -enable-experimental-feature KeyPathWithMethodMembers -emit-module -emit-library -enable-library-evolution -module-name LibA -o %t/%target-library-name(LibA) -emit-module-interface-path %t/LibA.swiftinterface
66

77
// Build LibB
8-
// RUN: %target-build-swift %t/src/LibB.swift -I %t -L %t -l LibA -swift-version 5 -emit-module -emit-library -module-name LibB -o %t/%target-library-name(LibB)
8+
// RUN: %target-build-swift %t/src/LibB.swift -I %t -L %t -l LibA -swift-version 5 -enable-experimental-feature KeyPathWithMethodMembers -emit-module -emit-library -module-name LibB -o %t/%target-library-name(LibB)
99

1010
// Build LibC
11-
// RUN: %target-build-swift %t/src/LibC.swift -I %t -L %t -l LibA -swift-version 5 -emit-module -emit-library -module-name LibC -o %t/%target-library-name(LibC)
11+
// RUN: %target-build-swift %t/src/LibC.swift -I %t -L %t -l LibA -swift-version 5 -enable-experimental-feature KeyPathWithMethodMembers -emit-module -emit-library -module-name LibC -o %t/%target-library-name(LibC)
1212

1313
// Build & run main.swift
1414
// RUN: %target-build-swift -I %t -L %t -l LibA -l LibB -l LibC %t/src/main.swift -o %t/a.out
@@ -20,6 +20,7 @@
2020

2121
// REQUIRES: executable_test
2222
// REQUIRES: OS=macosx
23+
// REQUIRES: swift_feature_KeyPathWithMethodMembers
2324

2425
// UNSUPPORTED: use_os_stdlib
2526
// UNSUPPORTED: back_deployment_runtime

test/SILGen/keypaths.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -target %target-swift-5.1-abi-triple -parse-stdlib -module-name keypaths %s | %FileCheck %s
1+
// RUN: %target-swift-emit-silgen -enable-experimental-feature KeyPathWithMethodMembers -Xllvm -sil-print-types -target %target-swift-5.1-abi-triple -parse-stdlib -module-name keypaths %s | %FileCheck %s
2+
// REQUIRES: swift_feature_KeyPathWithMethodMembers
23

34
import Swift
45

test/attr/attr_dynamic_member_lookup.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature KeyPathWithMethodMembers
2+
// REQUIRES: swift_feature_KeyPathWithMethodMembers
23

34
var global = 42
45

test/expr/unary/keypath/keypath.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %target-swift-frontend -typecheck -parse-as-library %s -verify
1+
// RUN: %target-swift-frontend -enable-experimental-feature KeyPathWithMethodMembers -typecheck -parse-as-library %s -verify
2+
// REQUIRES: swift_feature_KeyPathWithMethodMembers
23

34
struct Sub: Hashable {
45
static func ==(_: Sub, _: Sub) -> Bool { return true }

0 commit comments

Comments
 (0)