[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

This commit is contained in:
jreference
2023-04-30 10:19:02 +08:00
parent 2338b4cce3
commit 2cf01a18de
5 changed files with 89 additions and 20 deletions

View File

@@ -2577,7 +2577,6 @@ bool ContextualFailure::diagnoseAsError() {
}
return false;
}
case ConstraintLocator::UnresolvedMemberChainResult: {
auto &solution = getSolution();
@@ -3528,6 +3527,66 @@ ContextualFailure::getDiagnosticFor(ContextualTypePurpose context,
return None;
}
bool NonClassTypeToAnyObjectConversionFailure::diagnoseAsError() {
auto locator = getLocator();
if (locator->isForContextualType()) {
return ContextualFailure::diagnoseAsError();
}
auto fromType = getFromType();
auto toType = getToType();
assert(fromType);
assert(toType);
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
ArgumentMismatchFailure failure(getSolution(), fromType, toType, locator);
return failure.diagnoseAsError();
}
Optional<Diag<Type, Type>> diagnostic;
bool forProtocol = toType->isConstraintType();
auto rawAnchor = getRawAnchor();
if (isExpr<ArrayExpr>(rawAnchor)) {
diagnostic = forProtocol ? diag::cannot_convert_array_element_protocol
: diag::cannot_convert_array_element;
} else if (isExpr<DictionaryExpr>(rawAnchor)) {
auto lastElem = locator->getLastElementAs<LocatorPathElt::TupleElement>();
if (lastElem && lastElem->getIndex() == 0) {
diagnostic = forProtocol ? diag::cannot_convert_dict_key_protocol
: diag::cannot_convert_dict_key;
} else {
diagnostic = forProtocol ? diag::cannot_convert_dict_value_protocol
: diag::cannot_convert_dict_value;
}
} else if (toType->isAnyObject()) {
diagnostic = diag::cannot_convert_initializer_value_anyobject;
}
if (diagnostic.hasValue()) {
emitDiagnostic(*diagnostic, fromType, toType);
return true;
}
return false;
}
bool NonClassTypeToAnyObjectConversionFailure::diagnoseAsNote() {
auto *locator = getLocator();
if (locator->isForContextualType()) {
return ContextualFailure::diagnoseAsNote();
}
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
ArgumentMismatchFailure failure(getSolution(), getFromType(), getToType(),
getLocator());
return failure.diagnoseAsNote();
}
return false;
}
bool TupleContextualFailure::diagnoseAsError() {
Diag<Type, Type> diagnostic;
auto purpose = getContextualTypePurpose();

View File

@@ -804,6 +804,19 @@ protected:
}
};
class NonClassTypeToAnyObjectConversionFailure final
: public ContextualFailure {
public:
NonClassTypeToAnyObjectConversionFailure(const Solution &solution, Type lhs,
Type rhs, ConstraintLocator *locator)
: ContextualFailure(solution, lhs, rhs, locator, FixBehavior::Error) {}
bool diagnoseAsError() override;
bool diagnoseAsNote() override;
};
/// Diagnose errors related to using an array literal where a
/// dictionary is expected.
class ArrayLiteralToDictionaryConversionFailure final : public ContextualFailure {

View File

@@ -1934,18 +1934,10 @@ bool AllowNonClassTypeToConvertToAnyObject::diagnose(const Solution &solution,
bool asNote) const {
auto *locator = getLocator();
if (locator->isForContextualType()) {
ContextualFailure failure(solution, getFromType(), getToType(), locator);
return failure.diagnose(asNote);
}
NonClassTypeToAnyObjectConversionFailure failure(solution, getFromType(),
getToType(), locator);
if (locator->isLastElement<LocatorPathElt::ApplyArgToParam>()) {
ArgumentMismatchFailure failure(solution, getFromType(), getToType(),
locator);
return failure.diagnose(asNote);
}
return false;
return failure.diagnose(asNote);
}
AllowNonClassTypeToConvertToAnyObject *

View File

@@ -0,0 +1,9 @@
// RUN: %target-typecheck-verify-swift
let _: AnyObject = "a" // expected-error {{value of type 'String' expected to be instance of class or class-constrained type}}
let _: [AnyObject] = ["a"] // expected-error {{cannot convert value of type 'String' to expected element type 'AnyObject'}}
let _: [String: AnyObject] = ["a": "a"] // expected-error {{cannot convert value of type 'String' to expected dictionary value type 'AnyObject'}}
let _: [AnyObject: String] = ["a": "a"] // expected-error {{type 'AnyObject' does not conform to protocol 'Hashable'}}
// expected-error@-1 {{cannot convert value of type 'String' to expected dictionary key type 'AnyObject'}}
let _: (AnyObject, Void) = ("a", ()) // expected-error {{value of type 'String' expected to be instance of class or class-constrained type}}

View File

@@ -1,16 +1,13 @@
// RUN: %target-typecheck-verify-swift
protocol P {
subscript<Value>(x: Value) -> Int // expected-note {{protocol requires subscript with type '<Value> (Value) -> Int'; do you want to add a stub?}}
{
subscript<Value>(x: Value) -> Int { // expected-note {{protocol requires subscript with type '<Value> (Value) -> Int'; do you want to add a stub?}}
get
}
}
struct S: P // expected-error {{type 'S' does not conform to protocol 'P'}}
{
subscript<Value>(x: Int) -> Value // expected-note {{candidate has non-matching type '<Value> (Int) -> Value'}}
{
struct S : P { // expected-error {{type 'S' does not conform to protocol 'P'}}
subscript<Value>(x: Int) -> Value { // expected-note {{candidate has non-matching type '<Value> (Int) -> Value'}}
} // expected-error {{missing return in subscript expected to return 'Value'}}
}
@@ -21,8 +18,7 @@ struct S2: P {
}
protocol P2 {
subscript(x: Int) -> Int
{
subscript(x: Int) -> Int {
get
}
}