Skip to content

Commit bb5e557

Browse files
committed
Guard feature behind experimental flag.
1 parent bb3c205 commit bb5e557

15 files changed

+96
-35
lines changed

build.sh

-15
This file was deleted.

include/swift/Basic/Features.def

+1
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ EXPERIMENTAL_FEATURE(TupleConformances, false)
236236
EXPERIMENTAL_FEATURE(FullTypedThrows, false)
237237
EXPERIMENTAL_FEATURE(SameElementRequirements, false)
238238
EXPERIMENTAL_FEATURE(Span, true)
239+
EXPERIMENTAL_FEATURE(KeyPathWithMethodMembers, false)
239240

240241
// Whether to enable @_used and @_section attributes
241242
EXPERIMENTAL_FEATURE(SymbolLinkageMarkers, true)

include/swift/Sema/CSFix.h

+9
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,11 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
20062006
// a key path component.
20072007
MutatingGetter,
20082008
// Allow a reference to a mutating method.
2009+
Method,
2010+
// Allow a reference to a initializer instance as a key path
2011+
// component.
2012+
Initializer,
2013+
// Allow a reference to an enum case as a key path component.
20092014
MutatingMethod,
20102015
// Allow a reference to an async or throwing method.
20112016
AsyncOrThrowsMethod,
@@ -2032,6 +2037,10 @@ class AllowInvalidRefInKeyPath final : public ConstraintFix {
20322037
case RefKind::MutatingGetter:
20332038
return "allow reference to a member with mutating getter as a key "
20342039
"path component";
2040+
case RefKind::Method:
2041+
return "allow reference to a method as a key path component";
2042+
case RefKind::Initializer:
2043+
return "allow reference to an init method as a key path component";
20352044
case RefKind::EnumCase:
20362045
return "allow reference to an enum case as a key path component";
20372046
case RefKind::MutatingMethod:

lib/AST/FeatureSet.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ UNINTERESTING_FEATURE(SuppressedAssociatedTypes)
122122
UNINTERESTING_FEATURE(StructLetDestructuring)
123123
UNINTERESTING_FEATURE(MacrosOnImports)
124124
UNINTERESTING_FEATURE(NonIsolatedAsyncInheritsIsolationFromContext)
125+
UNINTERESTING_FEATURE(KeyPathWithMethodMembers)
125126

126127
static bool usesFeatureNonescapableTypes(Decl *decl) {
127128
auto containsNonEscapable =

lib/Sema/CSDiagnostics.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -6431,6 +6431,12 @@ bool InvalidMemberWithMutatingGetterInKeyPath::diagnoseAsError() {
64316431
return true;
64326432
}
64336433

6434+
bool InvalidMethodRefInKeyPath::diagnoseAsError() {
6435+
emitDiagnostic(diag::expr_keypath_not_property, getMember(),
6436+
isForKeyPathDynamicMemberLookup());
6437+
return true;
6438+
}
6439+
64346440
bool InvalidMutatingMethodRefInKeyPath::diagnoseAsError() {
64356441
emitDiagnostic(diag::expr_keypath_mutating_method, getMember(),
64366442
isForKeyPathDynamicMemberLookup());

lib/Sema/CSDiagnostics.h

+25
Original file line numberDiff line numberDiff line change
@@ -1807,6 +1807,31 @@ 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 e.g.
1812+
///
1813+
/// ```swift
1814+
/// struct S {
1815+
/// init() { }
1816+
/// func foo() -> Int { return 42 }
1817+
/// static func bar() -> Int { return 0 }
1818+
/// }
1819+
///
1820+
/// _ = \S.foo
1821+
/// _ = \S.Type.bar
1822+
/// _ = \S.init
1823+
/// ```
1824+
class InvalidMethodRefInKeyPath final : public InvalidMemberRefInKeyPath {
1825+
public:
1826+
InvalidMethodRefInKeyPath(const Solution &solution, ValueDecl *method,
1827+
ConstraintLocator *locator)
1828+
: InvalidMemberRefInKeyPath(solution, method, locator) {
1829+
assert(isa<FuncDecl>(method) || isa<ConstructorDecl>(method));
1830+
}
1831+
1832+
bool diagnoseAsError() override;
1833+
};
1834+
18101835
/// Diagnose an attempt to reference a mutating method as a key path component
18111836
/// e.g.
18121837
///

lib/Sema/CSFix.cpp

+35-11
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,11 @@ bool AllowInvalidRefInKeyPath::diagnose(const Solution &solution,
12481248
getLocator());
12491249
return failure.diagnose(asNote);
12501250
}
1251+
case RefKind::Method:
1252+
case RefKind::Initializer: {
1253+
InvalidMethodRefInKeyPath failure(solution, Member, getLocator());
1254+
return failure.diagnose(asNote);
1255+
}
12511256
case RefKind::MutatingMethod: {
12521257
InvalidMutatingMethodRefInKeyPath failure(solution, Member, getLocator());
12531258
return failure.diagnose(asNote);
@@ -1320,22 +1325,41 @@ AllowInvalidRefInKeyPath::forRef(ConstraintSystem &cs, Type baseType,
13201325
cs, baseType, RefKind::MutatingGetter, member, locator);
13211326
}
13221327

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

1352+
// Referencing (instance or static) methods in key path is
1353+
// not currently allowed.
1354+
if (isa<FuncDecl>(member))
1355+
return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Method,
1356+
member, locator);
1357+
1358+
// Referencing initializers in key path is not currently allowed.
1359+
if (isa<ConstructorDecl>(member))
1360+
return AllowInvalidRefInKeyPath::create(cs, baseType, RefKind::Initializer,
1361+
member, locator);
1362+
13391363
return nullptr;
13401364
}
13411365

lib/Sema/CSSimplify.cpp

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

1068310686
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)