Skip to content

Commit 02c454c

Browse files
[Diagnostics] Diagnose that we cannot infer the key path type when binding to a hole
1 parent 98d3a81 commit 02c454c

File tree

8 files changed

+98
-4
lines changed

8 files changed

+98
-4
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ ERROR(could_not_find_value_subscript,none,
5757
"value of type %0 has no subscripts",
5858
(Type))
5959

60+
ERROR(could_not_find_value_subscript_key_path,none,
61+
"value of type %0 has no matching subscript candidates; "
62+
"did you mean to use a key path subscript?",
63+
(Type))
64+
6065
ERROR(could_not_find_tuple_member,none,
6166
"value of tuple type %0 has no member %1", (Type, DeclNameRef))
6267

@@ -71,6 +76,11 @@ ERROR(could_not_find_value_dynamic_member_corrected,none,
7176
ERROR(could_not_find_value_dynamic_member,none,
7277
"value of type %0 has no dynamic member %2 using key path from root type %1",
7378
(Type, Type, DeclNameRef))
79+
ERROR(cannot_infer_contextual_keypath_type_specify_root,none,
80+
"cannot infer key path type from context; consider explicitly adding a root type", ())
81+
ERROR(cannot_infer_contextual_keypath_type_any_contextual,none,
82+
"'AnyKeyPath' does not provide enough context for root type to be inferred implicitly; "
83+
"consider explicitly adding a root type", ())
7484

7585
ERROR(could_not_find_type_member,none,
7686
"type %0 has no member %1", (Type, DeclNameRef))

lib/Sema/CSBindings.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,11 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
11071107
cs, TypeVar->getImpl().getLocator());
11081108
if (cs.recordFix(fix))
11091109
return true;
1110+
} else if (srcLocator->isKeyPathRoot()) {
1111+
auto *fix =
1112+
SpecifyKeyPathRootType::create(cs, TypeVar->getImpl().getLocator());
1113+
if (cs.recordFix(fix))
1114+
return true;
11101115
}
11111116
}
11121117
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6271,3 +6271,25 @@ bool MultiArgFuncKeyPathFailure::diagnoseAsError() {
62716271
resolveType(functionType));
62726272
return true;
62736273
}
6274+
6275+
bool UnableToInferKeyPathRootFailure::diagnoseAsError() {
6276+
assert(isExpr<KeyPathExpr>(getAnchor()) && "Expected key path expression");
6277+
auto &ctx = getASTContext();
6278+
auto contextualType = getContextualType(getAnchor());
6279+
auto *keyPathExpr = castToExpr<KeyPathExpr>(getAnchor());
6280+
6281+
auto emitKeyPathDiagnostic = [&]() {
6282+
if (contextualType &&
6283+
contextualType->getAnyNominal() == ctx.getAnyKeyPathDecl()) {
6284+
return emitDiagnostic(
6285+
diag::cannot_infer_contextual_keypath_type_any_contextual);
6286+
}
6287+
return emitDiagnostic(
6288+
diag::cannot_infer_contextual_keypath_type_specify_root);
6289+
};
6290+
6291+
emitKeyPathDiagnostic()
6292+
.highlight(keyPathExpr->getLoc())
6293+
.fixItInsertAfter(keyPathExpr->getStartLoc(), "<#Root#>");
6294+
return true;
6295+
}

lib/Sema/CSDiagnostics.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,21 @@ class MultiArgFuncKeyPathFailure final : public FailureDiagnostic {
20582058
bool diagnoseAsError() override;
20592059
};
20602060

2061+
/// Diagnose a failure to infer a KeyPath type by context.
2062+
///
2063+
/// ```swift
2064+
/// _ = \.x
2065+
/// let _ : AnyKeyPath = \.x
2066+
/// ```
2067+
class UnableToInferKeyPathRootFailure final : public FailureDiagnostic {
2068+
public:
2069+
UnableToInferKeyPathRootFailure(const Solution &solution,
2070+
ConstraintLocator *locator)
2071+
: FailureDiagnostic(solution, locator) {}
2072+
2073+
bool diagnoseAsError() override;
2074+
};
2075+
20612076
} // end namespace constraints
20622077
} // end namespace swift
20632078

lib/Sema/CSFix.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,3 +1323,17 @@ AllowKeyPathRootTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs,
13231323
return new (cs.getAllocator())
13241324
AllowKeyPathRootTypeMismatch(cs, lhs, rhs, locator);
13251325
}
1326+
1327+
SpecifyKeyPathRootType *
1328+
SpecifyKeyPathRootType::create(ConstraintSystem &cs,
1329+
ConstraintLocator *locator) {
1330+
return new (cs.getAllocator())
1331+
SpecifyKeyPathRootType(cs, locator);
1332+
}
1333+
1334+
bool SpecifyKeyPathRootType::diagnose(const Solution &solution,
1335+
bool asNote) const {
1336+
UnableToInferKeyPathRootFailure failure(solution, getLocator());
1337+
1338+
return failure.diagnose(asNote);
1339+
}

lib/Sema/CSFix.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,11 @@ enum class FixKind : uint8_t {
259259
AllowKeyPathRootTypeMismatch,
260260

261261
/// Allow key path to be bound to a function type with more than 1 argument
262-
AllowMultiArgFuncKeyPathMismatch
262+
AllowMultiArgFuncKeyPathMismatch,
263+
264+
/// Specify key path root type when it cannot be infered by context.
265+
SpecifyKeyPathRootType,
266+
263267
};
264268

265269
class ConstraintFix {
@@ -1823,6 +1827,21 @@ class AllowKeyPathRootTypeMismatch : public ContextualMismatch {
18231827
create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator);
18241828
};
18251829

1830+
class SpecifyKeyPathRootType : public ConstraintFix {
1831+
SpecifyKeyPathRootType(ConstraintSystem &cs, ConstraintLocator *locator)
1832+
: ConstraintFix(cs, FixKind::SpecifyKeyPathRootType, locator) {}
1833+
1834+
public:
1835+
std::string getName() const {
1836+
return "specify key path root type";
1837+
}
1838+
1839+
bool diagnose(const Solution &solution, bool asNote = false) const;
1840+
1841+
static SpecifyKeyPathRootType *create(ConstraintSystem &cs,
1842+
ConstraintLocator *locator);
1843+
};
1844+
18261845
} // end namespace constraints
18271846
} // end namespace swift
18281847

lib/Sema/CSGen.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3398,7 +3398,8 @@ namespace {
33983398
auto rootLocator =
33993399
CS.getConstraintLocator(E, ConstraintLocator::KeyPathRoot);
34003400
auto locator = CS.getConstraintLocator(E);
3401-
Type root = CS.createTypeVariable(rootLocator, TVO_CanBindToNoEscape);
3401+
Type root = CS.createTypeVariable(rootLocator, TVO_CanBindToNoEscape |
3402+
TVO_CanBindToHole);
34023403

34033404
// If a root type was explicitly given, then resolve it now.
34043405
if (auto rootRepr = E->getRootType()) {
@@ -3540,7 +3541,8 @@ namespace {
35403541
// path components.
35413542
auto typeLoc =
35423543
CS.getConstraintLocator(locator, ConstraintLocator::KeyPathType);
3543-
Type kpTy = CS.createTypeVariable(typeLoc, TVO_CanBindToNoEscape);
3544+
Type kpTy = CS.createTypeVariable(typeLoc, TVO_CanBindToNoEscape |
3545+
TVO_CanBindToHole);
35443546
CS.addKeyPathConstraint(kpTy, root, rvalueBase, componentTypeVars,
35453547
locator);
35463548
return kpTy;

lib/Sema/CSSimplify.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7663,6 +7663,12 @@ ConstraintSystem::simplifyKeyPathConstraint(
76637663

76647664
return true;
76657665
};
7666+
7667+
// We have a hole, the solver can't infer the key path type. So let's
7668+
// just assume this is solved.
7669+
if (shouldAttemptFixes() && keyPathTy->isHole()) {
7670+
return SolutionKind::Solved;
7671+
}
76667672

76677673
// If we're fixed to a bound generic type, trying harvesting context from it.
76687674
// However, we don't want a solution that fixes the expression type to
@@ -9482,7 +9488,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
94829488
case FixKind::CoerceToCheckedCast:
94839489
case FixKind::SpecifyObjectLiteralTypeImport:
94849490
case FixKind::AllowKeyPathRootTypeMismatch:
9485-
case FixKind::AllowCoercionToForceCast: {
9491+
case FixKind::AllowCoercionToForceCast:
9492+
case FixKind::SpecifyKeyPathRootType: {
94869493
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
94879494
}
94889495

0 commit comments

Comments
 (0)