Skip to content

Commit 552106d

Browse files
authored
Merge pull request swiftlang#80081 from xedin/rdar-143161190
[CSSimplify] Open key path type before assignment to its record requirements
2 parents adc995f + cfad698 commit 552106d

File tree

8 files changed

+110
-4
lines changed

8 files changed

+110
-4
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,8 @@ ERROR(expr_keypath_generic_type,none,
667667
"key path cannot refer to generic type %0", (Identifier))
668668
ERROR(expr_keypath_noncopyable_type,none,
669669
"key path cannot refer to noncopyable type %0", (Type))
670+
ERROR(expr_keypath_nonescapable_type,none,
671+
"key path cannot refer to nonescapable type %0", (Type))
670672
ERROR(expr_keypath_not_property,none,
671673
"%select{key path|dynamic key path member lookup}1 cannot refer to %kind0",
672674
(const ValueDecl *, bool))

include/swift/Sema/ConstraintSystem.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4176,6 +4176,21 @@ class ConstraintSystem {
41764176
bool resolveTapBody(TypeVariableType *typeVar, Type contextualType,
41774177
ConstraintLocatorBuilder locator);
41784178

4179+
/// Bind key path expression to the given contextual type and generate
4180+
/// constraints for its requirements.
4181+
///
4182+
/// \param typeVar The type variable representing the key path expression.
4183+
/// \param contextualType The contextual type this key path expression
4184+
/// would be bound to.
4185+
/// \param flags The flags associated with this assignment.
4186+
/// \param locator The locator associated with contextual type.
4187+
///
4188+
/// \returns `true` if it was possible to generate constraints for
4189+
/// the requirements and assign fixed type to the key path expression,
4190+
/// `false` otherwise.
4191+
bool resolveKeyPath(TypeVariableType *typeVar, Type contextualType,
4192+
TypeMatchOptions flags, ConstraintLocatorBuilder locator);
4193+
41794194
/// Assign a fixed type to the given type variable.
41804195
///
41814196
/// \param typeVar The type variable to bind.

lib/Sema/CSDiagnostics.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,20 @@ bool MissingConformanceFailure::diagnoseAsError() {
684684
}
685685
}
686686

687+
if (isExpr<KeyPathExpr>(anchor)) {
688+
if (auto *P = dyn_cast<ProtocolDecl>(protocolType->getAnyNominal())) {
689+
if (P->isSpecificProtocol(KnownProtocolKind::Copyable)) {
690+
emitDiagnostic(diag::expr_keypath_noncopyable_type, nonConformingType);
691+
return true;
692+
}
693+
694+
if (P->isSpecificProtocol(KnownProtocolKind::Escapable)) {
695+
emitDiagnostic(diag::expr_keypath_nonescapable_type, nonConformingType);
696+
return true;
697+
}
698+
}
699+
}
700+
687701
if (diagnoseAsAmbiguousOperatorRef())
688702
return true;
689703

lib/Sema/CSSimplify.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4675,6 +4675,12 @@ ConstraintSystem::matchTypesBindTypeVar(
46754675
: getTypeMatchFailure(locator);
46764676
}
46774677

4678+
if (typeVar->getImpl().isKeyPathType()) {
4679+
return resolveKeyPath(typeVar, type, flags, locator)
4680+
? getTypeMatchSuccess()
4681+
: getTypeMatchFailure(locator);
4682+
}
4683+
46784684
assignFixedType(typeVar, type, /*updateState=*/true,
46794685
/*notifyInference=*/!flags.contains(TMF_BindingTypeVariable));
46804686

@@ -12257,6 +12263,30 @@ bool ConstraintSystem::resolveTapBody(TypeVariableType *typeVar,
1225712263
return !generateConstraints(tapExpr);
1225812264
}
1225912265

12266+
bool ConstraintSystem::resolveKeyPath(TypeVariableType *typeVar,
12267+
Type contextualType,
12268+
TypeMatchOptions flags,
12269+
ConstraintLocatorBuilder locator) {
12270+
// Key path types recently gained Copyable, Escapable requirements.
12271+
// The solver cannot account for that during inference because Root
12272+
// and Value types are required to be only resolved enough to infer
12273+
// a capability of a key path itself.
12274+
if (auto *BGT = contextualType->getAs<BoundGenericType>()) {
12275+
auto keyPathTy = openUnboundGenericType(
12276+
BGT->getDecl(), BGT->getParent(), locator, /*isTypeResolution=*/false);
12277+
12278+
assignFixedType(
12279+
typeVar, keyPathTy, /*updateState=*/true,
12280+
/*notifyInference=*/!flags.contains(TMF_BindingTypeVariable));
12281+
addConstraint(ConstraintKind::Equal, keyPathTy, contextualType, locator);
12282+
return true;
12283+
}
12284+
12285+
assignFixedType(typeVar, contextualType, /*updateState=*/true,
12286+
/*notifyInference=*/!flags.contains(TMF_BindingTypeVariable));
12287+
return true;
12288+
}
12289+
1226012290
ConstraintSystem::SolutionKind
1226112291
ConstraintSystem::simplifyDynamicTypeOfConstraint(
1226212292
Type type1, Type type2,

test/Constraints/keypath.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,24 @@ extension Collection {
318318
func keypathToFunctionWithOptional() {
319319
_ = Array("").prefix(1...4, while: \.isNumber) // Ok
320320
}
321+
322+
func test_new_key_path_type_requirements() {
323+
struct V: ~Copyable {
324+
}
325+
326+
struct S: ~Copyable {
327+
var x: Int
328+
var v: V
329+
}
330+
331+
_ = \S.x // expected-error {{key path cannot refer to noncopyable type 'S'}}
332+
_ = \S.v
333+
// expected-error@-1 {{key path cannot refer to noncopyable type 'S'}}
334+
// expected-error@-2 {{key path cannot refer to noncopyable type 'V'}}
335+
336+
func test<R>(_: KeyPath<R, Int>) {} // expected-note {{'where R: Copyable' is implicit here}}
337+
338+
test(\S.x)
339+
// expected-error@-1 {{key path cannot refer to noncopyable type 'S'}}
340+
// expected-error@-2 {{local function 'test' requires that 'S' conform to 'Copyable'}}
341+
}

test/Sema/keypaths_noncopyable.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,18 @@ struct C {
3939

4040
// rdar://109287447
4141
public func testKeypath<V: ~Copyable>(m: consuming M<V>) {
42-
_ = m[keyPath: \.nc] // expected-error {{key path cannot refer to noncopyable type 'NC'}}
43-
_ = m[keyPath: \.nc.data] // expected-error {{key path cannot refer to noncopyable type 'NC'}}
44-
_ = m[keyPath: \.ncg] // expected-error {{key path cannot refer to noncopyable type 'V'}}
45-
_ = m[keyPath: \.ncg.protocolProp] // expected-error {{key path cannot refer to noncopyable type 'V'}}
42+
_ = m[keyPath: \.nc]
43+
// expected-error@-1 {{key path cannot refer to noncopyable type 'M<V>'}}
44+
// expected-error@-2 {{key path cannot refer to noncopyable type 'NC'}}
45+
_ = m[keyPath: \.nc.data]
46+
// expected-error@-1 {{key path cannot refer to noncopyable type 'M<V>'}}
47+
_ = m[keyPath: \.ncg]
48+
// expected-error@-1 {{key path cannot refer to noncopyable type 'M<V>'}}
49+
// expected-error@-2 {{key path cannot refer to noncopyable type 'V'}}
50+
_ = m[keyPath: \.ncg.protocolProp]
51+
// expected-error@-1 {{key path cannot refer to noncopyable type 'M<V>'}}
4652
_ = m[keyPath: \.string]
53+
// expected-error@-1 {{key path cannot refer to noncopyable type 'M<V>'}}
4754

4855
let b = Box(NC())
4956
_ = b.with(\.data)

test/Sema/lifetime_attr.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,18 @@ func invalidTarget(_ result: inout NE, _ source: consuming NE) { // expected-err
4444
func immortalConflict(_ immortal: Int) -> NE { // expected-error{{conflict between the parameter name and 'immortal' contextual keyword}}
4545
NE()
4646
}
47+
48+
do {
49+
struct Test: ~Escapable {
50+
var v1: Int
51+
var v2: NE
52+
}
53+
54+
_ = \Test.v1 // expected-error {{key path cannot refer to nonescapable type 'Test'}}
55+
_ = \Test.v2 // expected-error {{key path cannot refer to nonescapable type 'Test'}} expected-error {{key path cannot refer to nonescapable type 'NE'}}
56+
57+
func use(t: Test) {
58+
t[keyPath: \.v1] // expected-error {{key path cannot refer to nonescapable type 'Test'}}
59+
t[keyPath: \.v2] // expected-error {{key path cannot refer to nonescapable type 'Test'}} expected-error {{key path cannot refer to nonescapable type 'NE'}}
60+
}
61+
}

test/expr/unary/keypath/keypath.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,9 @@ func testKeyPathHole() {
945945

946946
func f(_ i: Int) {}
947947
f(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}
948+
// expected-error@-1 {{cannot convert value of type 'KeyPath<Root, Value>' to expected argument type 'Int'}}
948949
f(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}
950+
// expected-error@-1 {{cannot convert value of type 'KeyPath<Root, Value>' to expected argument type 'Int'}}
949951

950952
func provideValueButNotRoot<T>(_ fn: (T) -> String) {} // expected-note 2 {{in call to function 'provideValueButNotRoot'}}
951953
provideValueButNotRoot(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}

0 commit comments

Comments
 (0)