Skip to content

[Diagnostics] Removing FailureDiagnosis::visitCoerceExpr from CSDiag #29064

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{

bool visitSubscriptExpr(SubscriptExpr *SE);
bool visitApplyExpr(ApplyExpr *AE);
bool visitCoerceExpr(CoerceExpr *CE);
bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E);
};
} // end anonymous namespace
Expand Down Expand Up @@ -1878,17 +1877,6 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
return true;
}

bool FailureDiagnosis::visitCoerceExpr(CoerceExpr *CE) {
// Coerce the input to whatever type is specified by the CoerceExpr.
auto expr = typeCheckChildIndependently(CE->getSubExpr(),
CS.getType(CE->getCastTypeLoc()),
CTP_CoerceOperand);
if (!expr)
return true;

return false;
}

bool FailureDiagnosis::
visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
// Don't walk the children for this node, it leads to multiple diagnostics
Expand Down
11 changes: 9 additions & 2 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1905,6 +1905,12 @@ bool ContextualFailure::diagnoseAsError() {
diagnostic = diag::cannot_convert_condition_value;
break;
}

case ConstraintLocator::InstanceType: {
if (diagnoseCoercionToUnrelatedType())
return true;
break;
}

case ConstraintLocator::TernaryBranch: {
auto *ifExpr = cast<IfExpr>(getRawAnchor());
Expand Down Expand Up @@ -2235,11 +2241,12 @@ bool ContextualFailure::diagnoseCoercionToUnrelatedType() const {
auto *anchor = getAnchor();

if (auto *coerceExpr = dyn_cast<CoerceExpr>(anchor)) {
auto fromType = getFromType();
auto fromType = getType(coerceExpr->getSubExpr());
auto toType = getType(coerceExpr->getCastTypeLoc());

auto diagnostic =
getDiagnosticFor(CTP_CoerceOperand,
/*forProtocol=*/toType->isAnyExistentialType());
/*forProtocol=*/toType->isExistentialType());

auto diag =
emitDiagnostic(anchor->getLoc(), *diagnostic, fromType, toType);
Expand Down
46 changes: 40 additions & 6 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2200,9 +2200,19 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
}
} else { // There are no elements in the path
auto *anchor = locator.getAnchor();
if (!(anchor && isa<AssignExpr>(anchor)))
if (!(anchor &&
(isa<AssignExpr>(anchor) || isa<CoerceExpr>(anchor))))
return getTypeMatchFailure(locator);
}

auto *anchor = locator.getAnchor();
if (isa<CoerceExpr>(anchor)) {
auto *fix = ContextualMismatch::create(
*this, type1, type2, getConstraintLocator(locator));
if (recordFix(fix))
return getTypeMatchFailure(locator);
break;
}

auto *fix = MissingConformance::forContextual(
*this, type1, proto, getConstraintLocator(locator));
Expand Down Expand Up @@ -2830,10 +2840,16 @@ bool ConstraintSystem::repairFailures(
conversionsOrFixes.push_back(coerceToCheckCastFix);
return true;
}

// If it has a deep equality restriction, defer the diagnostic to
// GenericMismatch.
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality))
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) &&
!hasConversionOrRestriction(
ConversionRestrictionKind::OptionalToOptional)) {
return false;
}

if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
return false;

auto *fix = ContextualMismatch::create(*this, lhs, rhs,
Expand Down Expand Up @@ -3492,6 +3508,13 @@ bool ConstraintSystem::repairFailures(
break;
}
}
// Handle function result coerce expression wrong type conversion.
if (isa<CoerceExpr>(anchor)) {
auto *fix =
ContextualMismatch::create(*this, lhs, rhs, loc);
conversionsOrFixes.push_back(fix);
break;
}
LLVM_FALLTHROUGH;
}

Expand Down Expand Up @@ -4059,9 +4082,20 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
subKind = ConstraintKind::Bind;
}

return matchTypes(
instanceType1, instanceType2, subKind, subflags,
locator.withPathElement(ConstraintLocator::InstanceType));
auto result =
matchTypes(instanceType1, instanceType2, subKind, subflags,
locator.withPathElement(ConstraintLocator::InstanceType));
if (shouldAttemptFixes() && result.isFailure()) {
auto *anchor = locator.getAnchor();
if (anchor && isa<CoerceExpr>(anchor)) {
auto *fix =
ContextualMismatch::create(*this, instanceType1, instanceType2,
getConstraintLocator(locator));
conversionsOrFixes.push_back(fix);
break;
}
}
return result;
}

case TypeKind::Function: {
Expand Down
4 changes: 2 additions & 2 deletions test/ClangImporter/objc_parse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -550,8 +550,8 @@ func testProtocolQualified(_ obj: CopyableNSObject, cell: CopyableSomeCell,
_ = cell as NSCopying
_ = cell as SomeCell

_ = plainObj as CopyableNSObject // expected-error {{'NSObject' is not convertible to 'CopyableNSObject' (aka 'NSCopying & NSObjectProtocol'); did you mean to use 'as!' to force downcast?}} {{16-18=as!}}
_ = plainCell as CopyableSomeCell // expected-error {{'SomeCell' is not convertible to 'CopyableSomeCell' (aka 'SomeCell & NSCopying'); did you mean to use 'as!' to force downcast?}}
_ = plainObj as CopyableNSObject // expected-error {{value of type 'NSObject' does not conform to 'CopyableNSObject' (aka 'NSCopying & NSObjectProtocol') in coercion}}
_ = plainCell as CopyableSomeCell // expected-error {{value of type 'SomeCell' does not conform to 'CopyableSomeCell' (aka 'SomeCell & NSCopying') in coercion}}
}

extension Printing {
Expand Down
2 changes: 1 addition & 1 deletion test/Generics/function_defs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func otherExistential<T : EqualComparable>(_ t1: T) {
otherEqComp2 = t1 // expected-error{{value of type 'T' does not conform to 'OtherEqualComparable' in assignment}}
_ = otherEqComp2

_ = t1 as EqualComparable & OtherEqualComparable // expected-error{{'T' is not convertible to 'EqualComparable & OtherEqualComparable'; did you mean to use 'as!' to force downcast?}} {{10-12=as!}} expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}} expected-error{{protocol 'EqualComparable' can only be used as a generic constraint}}
_ = t1 as EqualComparable & OtherEqualComparable // expected-error{{value of type 'T' does not conform to 'EqualComparable & OtherEqualComparable' in coercion}} expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}} expected-error{{protocol 'EqualComparable' can only be used as a generic constraint}}
}

protocol Runcible {
Expand Down
4 changes: 2 additions & 2 deletions test/decl/protocol/protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ struct Circle {
func testCircular(_ circle: Circle) {
// FIXME: It would be nice if this failure were suppressed because the protocols
// have circular definitions.
_ = circle as CircleStart // expected-error{{'Circle' is not convertible to 'CircleStart'; did you mean to use 'as!' to force downcast?}} {{14-16=as!}}
_ = circle as CircleStart // expected-error{{value of type 'Circle' does not conform to 'CircleStart' in coercion}}
}

// <rdar://problem/14750346>
Expand Down Expand Up @@ -482,7 +482,7 @@ func f<T : C1>(_ x : T) {

class C2 {}
func g<T : C2>(_ x : T) {
x as P2 // expected-error{{'T' is not convertible to 'P2'; did you mean to use 'as!' to force downcast?}} {{5-7=as!}}
x as P2 // expected-error{{value of type 'T' does not conform to 'P2' in coercion}}
}

class C3 : P1 {} // expected-error{{type 'C3' does not conform to protocol 'P1'}}
Expand Down