Skip to content

Commit 2cf01a1

Browse files
author
jreference
committed
[Sema] Fix issue 65330 Unhelpful error when missing contextually required as bridging conversion to AnyObject in structural position. Minor formatting change in previous test case
1 parent 2338b4c commit 2cf01a1

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
@@ -2577,7 +2577,6 @@ bool ContextualFailure::diagnoseAsError() {
25772577
}
25782578
return false;
25792579
}
2580-
25812580
case ConstraintLocator::UnresolvedMemberChainResult: {
25822581
auto &solution = getSolution();
25832582

@@ -3528,6 +3527,66 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
35283527
return None;
35293528
}
35303529

3530+
bool NonClassTypeToAnyObjectConversionFailure::diagnoseAsError() {
3531+
auto locator = getLocator();
3532+
if (locator->isForContextualType()) {
3533+
return ContextualFailure::diagnoseAsError();
3534+
}
3535+
3536+
auto fromType = getFromType();
3537+
auto toType = getToType();
3538+
assert(fromType);
3539+
assert(toType);
3540+
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
3541+
ArgumentMismatchFailure failure(getSolution(), fromType, toType, locator);
3542+
return failure.diagnoseAsError();
3543+
}
3544+
3545+
Optional<Diag<Type, Type>> diagnostic;
3546+
3547+
bool forProtocol = toType->isConstraintType();
3548+
auto rawAnchor = getRawAnchor();
3549+
3550+
if (isExpr<ArrayExpr>(rawAnchor)) {
3551+
diagnostic = forProtocol ? diag::cannot_convert_array_element_protocol
3552+
: diag::cannot_convert_array_element;
3553+
} else if (isExpr<DictionaryExpr>(rawAnchor)) {
3554+
auto lastElem = locator->getLastElementAs<LocatorPathElt::TupleElement>();
3555+
if (lastElem && lastElem->getIndex() == 0) {
3556+
diagnostic = forProtocol ? diag::cannot_convert_dict_key_protocol
3557+
: diag::cannot_convert_dict_key;
3558+
} else {
3559+
diagnostic = forProtocol ? diag::cannot_convert_dict_value_protocol
3560+
: diag::cannot_convert_dict_value;
3561+
}
3562+
} else if (toType->isAnyObject()) {
3563+
diagnostic = diag::cannot_convert_initializer_value_anyobject;
3564+
}
3565+
3566+
if (diagnostic.hasValue()) {
3567+
emitDiagnostic(*diagnostic, fromType, toType);
3568+
return true;
3569+
}
3570+
3571+
return false;
3572+
}
3573+
3574+
bool NonClassTypeToAnyObjectConversionFailure::diagnoseAsNote() {
3575+
auto *locator = getLocator();
3576+
3577+
if (locator->isForContextualType()) {
3578+
return ContextualFailure::diagnoseAsNote();
3579+
}
3580+
3581+
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
3582+
ArgumentMismatchFailure failure(getSolution(), getFromType(), getToType(),
3583+
getLocator());
3584+
return failure.diagnoseAsNote();
3585+
}
3586+
3587+
return false;
3588+
}
3589+
35313590
bool TupleContextualFailure::diagnoseAsError() {
35323591
Diag<Type, Type> diagnostic;
35333592
auto purpose = getContextualTypePurpose();

lib/Sema/CSDiagnostics.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,19 @@ class ContextualFailure : public FailureDiagnostic {
804804
}
805805
};
806806

807+
class NonClassTypeToAnyObjectConversionFailure final
808+
: public ContextualFailure {
809+
810+
public:
811+
NonClassTypeToAnyObjectConversionFailure(const Solution &solution, Type lhs,
812+
Type rhs, ConstraintLocator *locator)
813+
: ContextualFailure(solution, lhs, rhs, locator, FixBehavior::Error) {}
814+
815+
bool diagnoseAsError() override;
816+
817+
bool diagnoseAsNote() override;
818+
};
819+
807820
/// Diagnose errors related to using an array literal where a
808821
/// dictionary is expected.
809822
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)