Skip to content

Commit 28fa3ab

Browse files
authored
Merge pull request #31848 from LucianoPAlmeida/SR-12827-keypath-hole
[SR-12827] [Diagnostics] Improve diagnostics keypath hole involving generic argument
2 parents 4069030 + bbd6d53 commit 28fa3ab

File tree

4 files changed

+55
-14
lines changed

4 files changed

+55
-14
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,12 +1088,22 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
10881088

10891089
ConstraintFix *fix = nullptr;
10901090
if (auto *GP = TypeVar->getImpl().getGenericParameter()) {
1091-
auto path = dstLocator->getPath();
1092-
// Drop `generic parameter` locator element so that all missing
1093-
// generic parameters related to the same path can be coalesced later.
1094-
fix = DefaultGenericArgument::create(
1095-
cs, GP,
1096-
cs.getConstraintLocator(dstLocator->getAnchor(), path.drop_back()));
1091+
// If it is represetative for a key path root, let's emit a more
1092+
// specific diagnostic.
1093+
auto *keyPathRoot =
1094+
cs.isRepresentativeFor(TypeVar, ConstraintLocator::KeyPathRoot);
1095+
if (keyPathRoot) {
1096+
fix = SpecifyKeyPathRootType::create(
1097+
cs, keyPathRoot->getImpl().getLocator());
1098+
} else {
1099+
auto path = dstLocator->getPath();
1100+
// Drop `generic parameter` locator element so that all missing
1101+
// generic parameters related to the same path can be coalesced later.
1102+
fix = DefaultGenericArgument::create(
1103+
cs, GP,
1104+
cs.getConstraintLocator(dstLocator->getAnchor(),
1105+
path.drop_back()));
1106+
}
10971107
} else if (TypeVar->getImpl().isClosureParameterType()) {
10981108
fix = SpecifyClosureParameterType::create(cs, dstLocator);
10991109
} else if (TypeVar->getImpl().isClosureResultType()) {

lib/Sema/ConstraintSystem.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,31 @@ Type ConstraintSystem::getFixedTypeRecursive(Type type,
903903
return type;
904904
}
905905

906+
TypeVariableType *ConstraintSystem::isRepresentativeFor(
907+
TypeVariableType *typeVar, ConstraintLocator::PathElementKind kind) const {
908+
// We only attempt to look for this if type variable is
909+
// a representative.
910+
if (getRepresentative(typeVar) != typeVar)
911+
return nullptr;
912+
913+
auto &CG = getConstraintGraph();
914+
auto result = CG.lookupNode(typeVar);
915+
auto equivalence = result.first.getEquivalenceClass();
916+
auto member = llvm::find_if(equivalence, [=](TypeVariableType *eq) {
917+
auto *loc = eq->getImpl().getLocator();
918+
if (!loc)
919+
return false;
920+
921+
auto path = loc->getPath();
922+
return !path.empty() && path.back().getKind() == kind;
923+
});
924+
925+
if (member == equivalence.end())
926+
return nullptr;
927+
928+
return *member;
929+
}
930+
906931
/// Does a var or subscript produce an l-value?
907932
///
908933
/// \param baseType - the type of the base on which this object

lib/Sema/ConstraintSystem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3070,6 +3070,13 @@ class ConstraintSystem {
30703070
return typeVar->getImpl().getRepresentative(getSavedBindings());
30713071
}
30723072

3073+
/// Find if the given type variable is representative for a type
3074+
/// variable which last locator path element is of the specified kind.
3075+
/// If true returns the type variable which it is the representative for.
3076+
TypeVariableType *
3077+
isRepresentativeFor(TypeVariableType *typeVar,
3078+
ConstraintLocator::PathElementKind kind) const;
3079+
30733080
/// Gets the VarDecl associateed with resolvedOverload, and the type of the
30743081
/// storage wrapper if the decl has an associated storage wrapper.
30753082
Optional<std::pair<VarDecl *, Type>>

test/expr/unary/keypath/keypath.swift

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -906,16 +906,15 @@ func testKeyPathHole() {
906906
f(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}
907907
f(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}} {{6-6=<#Root#>}}
908908

909-
// FIXME(SR-12827): Instead of "generic parameter 'T' could not be inferred",
910-
// we should offer the same diagnostic as above.
911-
func provideValueButNotRoot<T>(_ fn: (T) -> String) {} // expected-note 2{{in call to function 'provideValueButNotRoot'}}
912-
provideValueButNotRoot(\.x) // expected-error {{generic parameter 'T' could not be inferred}}
913-
provideValueButNotRoot(\.x.y) // expected-error {{generic parameter 'T' could not be inferred}}
909+
func provideValueButNotRoot<T>(_ fn: (T) -> String) {}
910+
provideValueButNotRoot(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
911+
provideValueButNotRoot(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
914912
provideValueButNotRoot(\String.foo) // expected-error {{value of type 'String' has no member 'foo'}}
915913

916-
func provideKPValueButNotRoot<T>(_ kp: KeyPath<T, String>) {} // expected-note 3{{in call to function 'provideKPValueButNotRoot'}}
917-
provideKPValueButNotRoot(\.x) // expected-error {{generic parameter 'T' could not be inferred}}
918-
provideKPValueButNotRoot(\.x.y) // expected-error {{generic parameter 'T' could not be inferred}}
914+
func provideKPValueButNotRoot<T>(_ kp: KeyPath<T, String>) {} // expected-note {{in call to function 'provideKPValueButNotRoot'}}
915+
provideKPValueButNotRoot(\.x) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
916+
provideKPValueButNotRoot(\.x.y) // expected-error {{cannot infer key path type from context; consider explicitly specifying a root type}}
917+
919918
provideKPValueButNotRoot(\String.foo)
920919
// expected-error@-1 {{value of type 'String' has no member 'foo'}}
921920
// expected-error@-2 {{generic parameter 'T' could not be inferred}}

0 commit comments

Comments
 (0)