Skip to content

Commit c659323

Browse files
authored
Merge pull request #67597 from amritpan/kp-value-mismatch-diagnostic
[ConstraintSystem] Delay Contextual Type Fix record for key paths
2 parents 9dcd55b + cb98479 commit c659323

File tree

4 files changed

+54
-29
lines changed

4 files changed

+54
-29
lines changed

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3815,7 +3815,7 @@ namespace {
38153815
CS.getConstraintLocator(E, ConstraintLocator::KeyPathValue);
38163816
auto *value = CS.createTypeVariable(valueLocator, TVO_CanBindToNoEscape |
38173817
TVO_CanBindToHole);
3818-
CS.addConstraint(ConstraintKind::Equal, base, value, locator);
3818+
CS.addConstraint(ConstraintKind::Equal, base, value, valueLocator);
38193819
CS.recordKeyPath(E, root, value, CurDC);
38203820

38213821
// The result is a KeyPath from the root to the end component.

lib/Sema/CSSimplify.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5187,18 +5187,12 @@ bool ConstraintSystem::repairFailures(
51875187
// fix-up here unless last component has already a invalid type or
51885188
// instance fix recorded.
51895189
if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
5190-
auto i = kpExpr->getComponents().size() - 1;
5191-
auto lastCompLoc = getConstraintLocator(
5192-
locator.withPathElement(LocatorPathElt::KeyPathComponent(i)));
5193-
if (hasFixFor(lastCompLoc, FixKind::AllowTypeOrInstanceMember))
5194-
return true;
5195-
5196-
auto lastComponentType = lhs->lookThroughAllOptionalTypes();
5197-
auto keyPathResultType = rhs->lookThroughAllOptionalTypes();
5198-
5199-
// Propagate contextual information from/to keypath result type.
5200-
(void)matchTypes(lastComponentType, keyPathResultType, matchKind,
5201-
TMF_ApplyingFix, getConstraintLocator(locator));
5190+
if (isKnownKeyPathType(lhs) && isKnownKeyPathType(rhs)) {
5191+
// If we have keypath capabilities for both sides and one of the bases
5192+
// is unresolved, it is too early to record fix.
5193+
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality))
5194+
return false;
5195+
}
52025196

52035197
conversionsOrFixes.push_back(IgnoreContextualType::create(
52045198
*this, lhs, rhs, getConstraintLocator(locator)));
@@ -6611,6 +6605,22 @@ bool ConstraintSystem::repairFailures(
66116605
conversionsOrFixes.push_back(fix);
66126606
return true;
66136607
}
6608+
case ConstraintLocator::KeyPathValue: {
6609+
if (lhs->isPlaceholder() || rhs->isPlaceholder())
6610+
return true;
6611+
if (lhs->isTypeVariableOrMember() || rhs->isTypeVariableOrMember())
6612+
break;
6613+
6614+
auto kpExpr = castToExpr<KeyPathExpr>(anchor);
6615+
auto i = kpExpr->getComponents().size() - 1;
6616+
auto lastCompLoc =
6617+
getConstraintLocator(kpExpr, LocatorPathElt::KeyPathComponent(i));
6618+
if (hasFixFor(lastCompLoc, FixKind::AllowTypeOrInstanceMember))
6619+
return true;
6620+
6621+
conversionsOrFixes.push_back(IgnoreContextualType::create(
6622+
*this, lhs, rhs, getConstraintLocator(anchor)));
6623+
}
66146624
default:
66156625
break;
66166626
}

test/Constraints/diagnostics.swift

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,18 +1039,6 @@ class C2_47269 {
10391039
}
10401040
}
10411041

1042-
// rdar://problem/32101765 - Keypath diagnostics are not actionable/helpful
1043-
1044-
struct R32101765 { let prop32101765 = 0 }
1045-
let _: KeyPath<R32101765, Float> = \.prop32101765
1046-
// expected-error@-1 {{key path value type 'Int' cannot be converted to contextual type 'Float'}}
1047-
let _: KeyPath<R32101765, Float> = \R32101765.prop32101765
1048-
// expected-error@-1 {{key path value type 'Int' cannot be converted to contextual type 'Float'}}
1049-
let _: KeyPath<R32101765, Float> = \.prop32101765.unknown
1050-
// expected-error@-1 {{type 'Int' has no member 'unknown'}}
1051-
let _: KeyPath<R32101765, Float> = \R32101765.prop32101765.unknown
1052-
// expected-error@-1 {{type 'Int' has no member 'unknown'}}
1053-
10541042
// rdar://problem/32390726 - Bad Diagnostic: Don't suggest `var` to `let` when binding inside for-statement
10551043
for var i in 0..<10 { // expected-warning {{variable 'i' was never mutated; consider removing 'var' to make it constant}} {{5-9=}}
10561044
_ = i + 1
@@ -1565,18 +1553,18 @@ func testNilCoalescingOperatorRemoveFix() {
15651553
let _ = "" /* This is a comment */ ?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{13-43=}}
15661554

15671555
let _ = "" // This is a comment
1568-
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1567:13-1568:10=}}
1556+
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1555:13-1556:10=}}
15691557

15701558
let _ = "" // This is a comment
15711559
/*
15721560
* The blank line below is part of the test case, do not delete it
15731561
*/
15741562

1575-
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1570:13-1575:10=}}
1563+
?? "" // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1558:13-1563:10=}}
15761564

1577-
if ("" ?? // This is a comment // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1577:9-1578:9=}}
1565+
if ("" ?? // This is a comment // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{9-1566:9=}}
15781566
"").isEmpty {}
15791567

15801568
if ("" // This is a comment
1581-
?? "").isEmpty {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1580:9-1581:12=}}
1569+
?? "").isEmpty {} // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'String', so the right side is never used}} {{1568:9-1569:12=}}
15821570
}

test/Constraints/keypath.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,30 @@ func issue_65965() {
236236
writeKP = \.v
237237
// expected-error@-1 {{key path value type 'KeyPath<S, String>' cannot be converted to contextual type 'WritableKeyPath<S, String>'}}
238238
}
239+
240+
func test_any_key_path() {
241+
struct S {
242+
var v: String
243+
}
244+
245+
var anyKP: AnyKeyPath
246+
anyKP = \S.v
247+
anyKP = \.v
248+
// expected-error@-1 {{cannot infer key path type from context; consider explicitly specifying a root type}}
249+
}
250+
251+
// rdar://problem/32101765 - Keypath diagnostics are not actionable/helpful
252+
func rdar32101765() {
253+
struct R32101765 {
254+
let prop32101765 = 0
255+
}
256+
257+
let _: KeyPath<R32101765, Float> = \.prop32101765
258+
// expected-error@-1 {{key path value type 'Int' cannot be converted to contextual type 'Float'}}
259+
let _: KeyPath<R32101765, Float> = \R32101765.prop32101765
260+
// expected-error@-1 {{key path value type 'Int' cannot be converted to contextual type 'Float'}}
261+
let _: KeyPath<R32101765, Float> = \.prop32101765.unknown
262+
// expected-error@-1 {{type 'Int' has no member 'unknown'}}
263+
let _: KeyPath<R32101765, Float> = \R32101765.prop32101765.unknown
264+
// expected-error@-1 {{type 'Int' has no member 'unknown'}}
265+
}

0 commit comments

Comments
 (0)