Skip to content

Commit d8cca72

Browse files
committed
[Diagnostics] Hint contextual type diagnostics with expression type if known
Avoid a re-typecheck in `diagnoseContextualConversionError` if the expression type is already known and only return `true` if we know that at least one error diagnostic has been emitted otherwise there is a risk that type-check is going to return without any and fail in verifier. Resolves: rdar://problem/40002266 (cherry picked from commit 934351a)
1 parent 24e5778 commit d8cca72

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,8 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
886886
/// Attempt to produce a diagnostic for a mismatch between an expression's
887887
/// type and its assumed contextual type.
888888
bool diagnoseContextualConversionError(Expr *expr, Type contextualType,
889-
ContextualTypePurpose CTP);
889+
ContextualTypePurpose CTP,
890+
Type suggestedType = Type());
890891

891892
/// For an expression being type checked with a CTP_CalleeResult contextual
892893
/// type, try to diagnose a problem.
@@ -2780,7 +2781,8 @@ static bool tryDiagnoseNonEscapingParameterToEscaping(
27802781
}
27812782

27822783
bool FailureDiagnosis::diagnoseContextualConversionError(
2783-
Expr *expr, Type contextualType, ContextualTypePurpose CTP) {
2784+
Expr *expr, Type contextualType, ContextualTypePurpose CTP,
2785+
Type suggestedType) {
27842786
// If the constraint system has a contextual type, then we can test to see if
27852787
// this is the problem that prevents us from solving the system.
27862788
if (!contextualType) {
@@ -2799,9 +2801,13 @@ bool FailureDiagnosis::diagnoseContextualConversionError(
27992801
if (contextualType->is<InOutType>())
28002802
options |= TCC_AllowLValue;
28012803

2802-
auto recheckedExpr = typeCheckChildIndependently(expr, options);
2804+
auto *recheckedExpr = typeCheckChildIndependently(expr, options);
28032805
auto exprType = recheckedExpr ? CS.getType(recheckedExpr) : Type();
28042806

2807+
// If there is a suggested type and re-typecheck failed, let's use it.
2808+
if (!exprType)
2809+
exprType = suggestedType;
2810+
28052811
// If it failed and diagnosed something, then we're done.
28062812
if (!exprType)
28072813
return CS.TC.Diags.hadAnyError();
@@ -5402,7 +5408,11 @@ bool FailureDiagnosis::diagnoseCallContextualConversionErrors(
54025408
// If type-checking with contextual type didn't produce any results
54035409
// it means that we have a contextual mismatch.
54045410
if (withContextual.empty()) {
5405-
return diagnoseContextualConversionError(callExpr, contextualType, CTP);
5411+
// If there is just a single choice, we can hit contextual diagnostics
5412+
// about it in case re-typecheck fails.
5413+
Type exprType = withoutContextual.size() == 1 ? *withoutContextual.begin() : Type();
5414+
return diagnoseContextualConversionError(callExpr, contextualType, CTP,
5415+
exprType);
54065416
}
54075417

54085418
// If call produces a single type when type-checked with contextual

test/Constraints/diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ func r21684487() {
501501
var closures = Array<MyClosure>()
502502
let testClosure = {(list: [Int]) -> Bool in return true}
503503

504-
let closureIndex = closures.index{$0 === testClosure} // expected-error {{cannot check reference equality of functions; operands here have types '_' and '([Int]) -> Bool'}}
504+
let closureIndex = closures.index{$0 === testClosure} // expected-error {{cannot check reference equality of functions;}}
505505
}
506506

507507
// <rdar://problem/18397777> QoI: special case comparisons with nil

test/Constraints/rdar40002266.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -verify %s
2+
// REQUIRES: objc_interop
3+
4+
import Foundation
5+
6+
struct S {
7+
init<T: NSNumber>(_ num: T) {
8+
self.init(num != 0) // expected-error {{binary operator '!=' cannot be applied to operands of type 'T' and 'Int'}}
9+
// expected-note@-1 {{expected an argument list of type '(Int, Int)'}}
10+
}
11+
}

0 commit comments

Comments
 (0)