Skip to content

Commit ff52726

Browse files
authored
Merge pull request #65610 from jreference/65330-unhelpful-error-contextually-required-as
[Sema] Fix issue 65330 Unhelpful error when missing contextually requ…
2 parents c260792 + 2cf01a1 commit ff52726

File tree

5 files changed

+89
-20
lines changed

5 files changed

+89
-20
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2582,7 +2582,6 @@ bool ContextualFailure::diagnoseAsError() {
25822582
}
25832583
return false;
25842584
}
2585-
25862585
case ConstraintLocator::UnresolvedMemberChainResult: {
25872586
auto &solution = getSolution();
25882587

@@ -3515,6 +3514,66 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
35153514
return None;
35163515
}
35173516

3517+
bool NonClassTypeToAnyObjectConversionFailure::diagnoseAsError() {
3518+
auto locator = getLocator();
3519+
if (locator->isForContextualType()) {
3520+
return ContextualFailure::diagnoseAsError();
3521+
}
3522+
3523+
auto fromType = getFromType();
3524+
auto toType = getToType();
3525+
assert(fromType);
3526+
assert(toType);
3527+
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
3528+
ArgumentMismatchFailure failure(getSolution(), fromType, toType, locator);
3529+
return failure.diagnoseAsError();
3530+
}
3531+
3532+
Optional<Diag<Type, Type>> diagnostic;
3533+
3534+
bool forProtocol = toType->isConstraintType();
3535+
auto rawAnchor = getRawAnchor();
3536+
3537+
if (isExpr<ArrayExpr>(rawAnchor)) {
3538+
diagnostic = forProtocol ? diag::cannot_convert_array_element_protocol
3539+
: diag::cannot_convert_array_element;
3540+
} else if (isExpr<DictionaryExpr>(rawAnchor)) {
3541+
auto lastElem = locator->getLastElementAs<LocatorPathElt::TupleElement>();
3542+
if (lastElem && lastElem->getIndex() == 0) {
3543+
diagnostic = forProtocol ? diag::cannot_convert_dict_key_protocol
3544+
: diag::cannot_convert_dict_key;
3545+
} else {
3546+
diagnostic = forProtocol ? diag::cannot_convert_dict_value_protocol
3547+
: diag::cannot_convert_dict_value;
3548+
}
3549+
} else if (toType->isAnyObject()) {
3550+
diagnostic = diag::cannot_convert_initializer_value_anyobject;
3551+
}
3552+
3553+
if (diagnostic.hasValue()) {
3554+
emitDiagnostic(*diagnostic, fromType, toType);
3555+
return true;
3556+
}
3557+
3558+
return false;
3559+
}
3560+
3561+
bool NonClassTypeToAnyObjectConversionFailure::diagnoseAsNote() {
3562+
auto *locator = getLocator();
3563+
3564+
if (locator->isForContextualType()) {
3565+
return ContextualFailure::diagnoseAsNote();
3566+
}
3567+
3568+
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
3569+
ArgumentMismatchFailure failure(getSolution(), getFromType(), getToType(),
3570+
getLocator());
3571+
return failure.diagnoseAsNote();
3572+
}
3573+
3574+
return false;
3575+
}
3576+
35183577
bool TupleContextualFailure::diagnoseAsError() {
35193578
Diag<Type, Type> diagnostic;
35203579
auto purpose = getContextualTypePurpose();

lib/Sema/CSDiagnostics.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,19 @@ class ContextualFailure : public FailureDiagnostic {
800800
}
801801
};
802802

803+
class NonClassTypeToAnyObjectConversionFailure final
804+
: public ContextualFailure {
805+
806+
public:
807+
NonClassTypeToAnyObjectConversionFailure(const Solution &solution, Type lhs,
808+
Type rhs, ConstraintLocator *locator)
809+
: ContextualFailure(solution, lhs, rhs, locator, FixBehavior::Error) {}
810+
811+
bool diagnoseAsError() override;
812+
813+
bool diagnoseAsNote() override;
814+
};
815+
803816
/// Diagnose errors related to using an array literal where a
804817
/// dictionary is expected.
805818
class ArrayLiteralToDictionaryConversionFailure final : public ContextualFailure {

lib/Sema/CSFix.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,18 +1934,10 @@ bool AllowNonClassTypeToConvertToAnyObject::diagnose(const Solution &solution,
19341934
bool asNote) const {
19351935
auto *locator = getLocator();
19361936

1937-
if (locator->isForContextualType()) {
1938-
ContextualFailure failure(solution, getFromType(), getToType(), locator);
1939-
return failure.diagnose(asNote);
1940-
}
1937+
NonClassTypeToAnyObjectConversionFailure failure(solution, getFromType(),
1938+
getToType(), locator);
19411939

1942-
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
1943-
ArgumentMismatchFailure failure(solution, getFromType(), getToType(),
1944-
locator);
1945-
return failure.diagnose(asNote);
1946-
}
1947-
1948-
return false;
1940+
return failure.diagnose(asNote);
19491941
}
19501942

19511943
AllowNonClassTypeToConvertToAnyObject *
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
let _: AnyObject = "a" // expected-error {{value of type 'String' expected to be instance of class or class-constrained type}}
4+
5+
let _: [AnyObject] = ["a"] // expected-error {{cannot convert value of type 'String' to expected element type 'AnyObject'}}
6+
let _: [String: AnyObject] = ["a": "a"] // expected-error {{cannot convert value of type 'String' to expected dictionary value type 'AnyObject'}}
7+
let _: [AnyObject: String] = ["a": "a"] // expected-error {{type 'AnyObject' does not conform to protocol 'Hashable'}}
8+
// expected-error@-1 {{cannot convert value of type 'String' to expected dictionary key type 'AnyObject'}}
9+
let _: (AnyObject, Void) = ("a", ()) // expected-error {{value of type 'String' expected to be instance of class or class-constrained type}}

test/Sema/generic-subscript.swift

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
// RUN: %target-typecheck-verify-swift
22

33
protocol P {
4-
subscript<Value>(x: Value) -> Int // expected-note {{protocol requires subscript with type '<Value> (Value) -> Int'; do you want to add a stub?}}
5-
{
4+
subscript<Value>(x: Value) -> Int { // expected-note {{protocol requires subscript with type '<Value> (Value) -> Int'; do you want to add a stub?}}
65
get
76
}
87
}
98

10-
struct S: P // expected-error {{type 'S' does not conform to protocol 'P'}}
11-
{
12-
subscript<Value>(x: Int) -> Value // expected-note {{candidate has non-matching type '<Value> (Int) -> Value'}}
13-
{
9+
struct S : P { // expected-error {{type 'S' does not conform to protocol 'P'}}
10+
subscript<Value>(x: Int) -> Value { // expected-note {{candidate has non-matching type '<Value> (Int) -> Value'}}
1411
} // expected-error {{missing return in subscript expected to return 'Value'}}
1512
}
1613

@@ -21,8 +18,7 @@ struct S2: P {
2118
}
2219

2320
protocol P2 {
24-
subscript(x: Int) -> Int
25-
{
21+
subscript(x: Int) -> Int {
2622
get
2723
}
2824
}

0 commit comments

Comments
 (0)