Skip to content

Commit d7e0971

Browse files
authored
Merge pull request #36531 from LucianoPAlmeida/SR-14096-kp-as-fn
[Sema][SR-14096] Change conditions in which key path component mismatch fix are diagnosed
2 parents efbfbc4 + af370f1 commit d7e0971

File tree

4 files changed

+58
-4
lines changed

4 files changed

+58
-4
lines changed

lib/Sema/CSDiagnostics.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -5973,6 +5973,9 @@ bool ArgumentMismatchFailure::diagnoseAsError() {
59735973
if (diagnoseTrailingClosureMismatch())
59745974
return true;
59755975

5976+
if (diagnoseKeyPathAsFunctionResultMismatch())
5977+
return true;
5978+
59765979
auto argType = getFromType();
59775980
auto paramType = getToType();
59785981

@@ -6227,6 +6230,31 @@ bool ArgumentMismatchFailure::diagnoseTrailingClosureMismatch() const {
62276230
return true;
62286231
}
62296232

6233+
bool ArgumentMismatchFailure::diagnoseKeyPathAsFunctionResultMismatch() const {
6234+
auto argExpr = getArgExpr();
6235+
if (!isExpr<KeyPathExpr>(argExpr))
6236+
return false;
6237+
6238+
auto argType = getFromType();
6239+
auto paramType = getToType();
6240+
6241+
if (!isKnownKeyPathType(argType))
6242+
return false;
6243+
6244+
auto kpType = argType->castTo<BoundGenericType>();
6245+
auto kpRootType = kpType->getGenericArgs()[0];
6246+
auto kpValueType = kpType->getGenericArgs()[1];
6247+
6248+
auto paramFnType = paramType->getAs<FunctionType>();
6249+
if (!(paramFnType && paramFnType->getNumParams() == 1 &&
6250+
paramFnType->getParams().front().getPlainType()->isEqual(kpRootType)))
6251+
return false;
6252+
6253+
emitDiagnostic(diag::expr_smart_keypath_value_covert_to_contextual_type,
6254+
kpValueType, paramFnType->getResult());
6255+
return true;
6256+
}
6257+
62306258
void ExpandArrayIntoVarargsFailure::tryDropArrayBracketsFixIt(
62316259
const Expr *anchor) const {
62326260
// If this is an array literal, offer to remove the brackets and pass the

lib/Sema/CSDiagnostics.h

+6
Original file line numberDiff line numberDiff line change
@@ -1909,6 +1909,12 @@ class ArgumentMismatchFailure : public ContextualFailure {
19091909
/// closures being passed to non-closure parameters.
19101910
bool diagnoseTrailingClosureMismatch() const;
19111911

1912+
/// Tailored key path as function diagnostics for argument mismatches where
1913+
/// argument is a keypath expression that has a root type that matches a
1914+
/// function parameter, but keypath value don't match the function parameter
1915+
/// result value.
1916+
bool diagnoseKeyPathAsFunctionResultMismatch() const;
1917+
19121918
protected:
19131919
/// \returns The position of the argument being diagnosed, starting at 1.
19141920
unsigned getArgPosition() const { return Info.getArgPosition(); }

lib/Sema/CSSimplify.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -3795,10 +3795,13 @@ bool ConstraintSystem::repairFailures(
37953795
// there is going to be a constraint to match result of the
37963796
// member lookup to the generic parameter `V` of *KeyPath<R, V>
37973797
// type associated with key path expression, which we need to
3798-
// fix-up here.
3799-
if (isExpr<KeyPathExpr>(anchor)) {
3800-
auto *fnType = lhs->getAs<FunctionType>();
3801-
if (fnType && fnType->getResult()->isEqual(rhs))
3798+
// fix-up here unless last component has already a invalid type or
3799+
// instance fix recorded.
3800+
if (auto *kpExpr = getAsExpr<KeyPathExpr>(anchor)) {
3801+
auto i = kpExpr->getComponents().size() - 1;
3802+
auto lastCompLoc = getConstraintLocator(
3803+
locator.withPathElement(LocatorPathElt::KeyPathComponent(i)));
3804+
if (hasFixFor(lastCompLoc, FixKind::AllowTypeOrInstanceMember))
38023805
return true;
38033806

38043807
auto lastComponentType = lhs->lookThroughAllOptionalTypes();

test/expr/unary/keypath/keypath.swift

+17
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,7 @@ func test_keypath_with_method_refs() {
795795
}
796796

797797
let _: KeyPath<S, Int> = \.foo // expected-error {{key path cannot refer to instance method 'foo()'}}
798+
// expected-error@-1 {{key path value type '() -> Int' cannot be converted to contextual type 'Int'}}
798799
let _: KeyPath<S, Int> = \.bar // expected-error {{key path cannot refer to static member 'bar()'}}
799800
let _ = \S.Type.bar // expected-error {{key path cannot refer to static method 'bar()'}}
800801

@@ -1094,3 +1095,19 @@ func rdar74711236() {
10941095
}()
10951096
}
10961097
}
1098+
1099+
extension String {
1100+
var filterOut : (Self) throws -> Bool {
1101+
{ $0.contains("a") }
1102+
}
1103+
}
1104+
1105+
func test_kp_as_function_mismatch() {
1106+
let a : [String] = [ "asd", "bcd", "def" ]
1107+
1108+
let _ : (String) -> Bool = \.filterOut // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
1109+
_ = a.filter(\.filterOut) // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
1110+
let _ : (String) -> Bool = \String.filterOut // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
1111+
_ = a.filter(\String.filterOut) // expected-error{{key path value type '(String) throws -> Bool' cannot be converted to contextual type 'Bool'}}
1112+
1113+
}

0 commit comments

Comments
 (0)