Skip to content

Commit 009f69b

Browse files
committed
Merge pull request #2755 from CodaFi/triple-value-meal
2 parents 000d413 + 054f2ff commit 009f69b

File tree

7 files changed

+52
-18
lines changed

7 files changed

+52
-18
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,12 @@ ERROR(expression_too_complex,none,
130130
"expression was too complex to be solved in reasonable time; "
131131
"consider breaking up the expression into distinct sub-expressions", ())
132132

133-
ERROR(comparison_with_nil_illegal,none,
134-
"value of type %0 can never be nil, comparison isn't allowed",
133+
ERROR(value_type_comparison_with_nil_illegal_did_you_mean,none,
134+
"value of type %0 cannot be compared by reference; "
135+
"did you mean to compare by value?",
136+
(Type))
137+
ERROR(value_type_comparison_with_nil_illegal,none,
138+
"type %0 is not optional, value can never be nil",
135139
(Type))
136140

137141
ERROR(cannot_match_expr_pattern_with_value,none,

lib/Sema/CSDiag.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4311,8 +4311,25 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
43114311
if (isa<NilLiteralExpr>(rhsExpr->getValueProvidingExpr()) &&
43124312
!isUnresolvedOrTypeVarType(lhsType)) {
43134313
if (isNameOfStandardComparisonOperator(overloadName)) {
4314-
diagnose(callExpr->getLoc(), diag::comparison_with_nil_illegal, lhsType)
4315-
.highlight(lhsExpr->getSourceRange());
4314+
// Regardless of whether the type has reference or value semantics,
4315+
// comparison with nil is illegal, albeit for different reasons spelled
4316+
// out by the diagnosis.
4317+
if (lhsType->getAnyOptionalObjectType() &&
4318+
(overloadName == "!==" || overloadName == "===")) {
4319+
auto revisedName = overloadName;
4320+
revisedName.pop_back();
4321+
// If we made it here, then we're trying to perform a comparison with
4322+
// reference semantics rather than value semantics. The fixit will
4323+
// lop off the extra '=' in the operator.
4324+
diagnose(callExpr->getLoc(),
4325+
diag::value_type_comparison_with_nil_illegal_did_you_mean,
4326+
lhsType)
4327+
.fixItReplace(callExpr->getLoc(), revisedName);
4328+
} else {
4329+
diagnose(callExpr->getLoc(),
4330+
diag::value_type_comparison_with_nil_illegal, lhsType)
4331+
.highlight(lhsExpr->getSourceRange());
4332+
}
43164333
return true;
43174334
}
43184335
}

test/ClangModules/nullability.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import CoreCooling
66

77
func testSomeClass(_ sc: SomeClass, osc: SomeClass?) {
88
var ao1: AnyObject = sc.methodA(osc)
9-
if sc.methodA(osc) == nil { } // expected-error{{value of type 'AnyObject' can never be nil, comparison isn't allowed}}
9+
if sc.methodA(osc) == nil { } // expected-error{{type 'AnyObject' is not optional, value can never be nil}}
1010

1111
var ao2: AnyObject = sc.methodB(nil)
12-
if sc.methodA(osc) == nil { } // expected-error{{value of type 'AnyObject' can never be nil, comparison isn't allowed}}
12+
if sc.methodA(osc) == nil { } // expected-error{{type 'AnyObject' is not optional, value can never be nil}}
1313

1414
var ao3: AnyObject = sc.property // expected-error{{value of optional type 'AnyObject?' not unwrapped; did you mean to use '!' or '?'?}} {{35-35=!}}
1515
var ao3_ok: AnyObject? = sc.property // okay
1616

1717
var ao4: AnyObject = sc.methodD()
18-
if sc.methodD() == nil { } // expected-error{{value of type 'AnyObject' can never be nil, comparison isn't allowed}}
18+
if sc.methodD() == nil { } // expected-error{{type 'AnyObject' is not optional, value can never be nil}}
1919

2020
sc.methodE(sc)
2121
sc.methodE(osc) // expected-error{{value of optional type 'SomeClass?' not unwrapped; did you mean to use '!' or '?'?}} {{17-17=!}}
@@ -31,15 +31,15 @@ func testSomeClass(_ sc: SomeClass, osc: SomeClass?) {
3131
let ci: CInt = 1
3232
var sc2 = SomeClass(int: ci)
3333
var sc2a: SomeClass = sc2
34-
if sc2 == nil { } // expected-error{{value of type 'SomeClass' can never be nil, comparison isn't allowed}}
34+
if sc2 == nil { } // expected-error{{type 'SomeClass' is not optional, value can never be nil}}
3535

3636
var sc3 = SomeClass(double: 1.5)
3737
if sc3 == nil { } // okay
3838
var sc3a: SomeClass = sc3 // expected-error{{value of optional type 'SomeClass?' not unwrapped}} {{28-28=!}}
3939

4040
var sc4 = sc.returnMe()
4141
var sc4a: SomeClass = sc4
42-
if sc4 == nil { } // expected-error{{value of type 'SomeClass' can never be nil, comparison isn't allowed}}
42+
if sc4 == nil { } // expected-error{{type 'SomeClass' is not optional, value can never be nil}}
4343
}
4444

4545
// Nullability with CF types.

test/ClangModules/objc_failable_inits.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Foundation
77
func testDictionary() {
88
// -[NSDictionary init] returns non-nil.
99
var dictNonOpt = NSDictionary()
10-
if dictNonOpt == nil { } // expected-error{{value of type 'NSDictionary' can never be nil, comparison isn't allowed}}
10+
if dictNonOpt == nil { } // expected-error{{type 'NSDictionary' is not optional, value can never be nil}}
1111
}
1212

1313
func testString() throws {

test/Constraints/diagnostics.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ class r20201968C {
213213

214214
// <rdar://problem/21459429> QoI: Poor compilation error calling assert
215215
func r21459429(_ a : Int) {
216-
assert(a != nil, "ASSERT COMPILATION ERROR") // expected-error {{value of type 'Int' can never be nil, comparison isn't allowed}}
216+
assert(a != nil, "ASSERT COMPILATION ERROR") // expected-error {{type 'Int' is not optional, value can never be nil}}
217217
}
218218

219219

@@ -590,7 +590,7 @@ func r21684487() {
590590
func r18397777(_ d : r21447318?) {
591591
let c = r21447318()
592592

593-
if c != nil { // expected-error {{value of type 'r21447318' can never be nil, comparison isn't allowed}}
593+
if c != nil { // expected-error {{type 'r21447318' is not optional, value can never be nil}}
594594
}
595595

596596
if d { // expected-error {{optional type 'r21447318?' cannot be used as a boolean; test for '!= nil' instead}} {{6-6=(}} {{7-7= != nil)}}
@@ -765,3 +765,16 @@ func r21523291(_ bytes : UnsafeMutablePointer<UInt8>) {
765765
}
766766

767767

768+
// SR-1594: Wrong error description when using === on non-class types
769+
class SR1594 {
770+
func sr1594(bytes : UnsafeMutablePointer<Int>, _ i : Int?) {
771+
_ = (i === nil) // expected-error {{value of type 'Int?' cannot be compared by reference; did you mean to compare by value?}} {{12-15===}}
772+
_ = (bytes === nil) // expected-error {{type 'UnsafeMutablePointer<Int>' is not optional, value can never be nil}}
773+
_ = (self === nil) // expected-error {{type 'SR1594' is not optional, value can never be nil}}
774+
_ = (i !== nil) // expected-error {{value of type 'Int?' cannot be compared by reference; did you mean to compare by value?}} {{12-15=!=}}
775+
_ = (bytes !== nil) // expected-error {{type 'UnsafeMutablePointer<Int>' is not optional, value can never be nil}}
776+
_ = (self !== nil) // expected-error {{type 'SR1594' is not optional, value can never be nil}}
777+
}
778+
}
779+
780+

test/expr/cast/nil_value_to_optional.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ var f = false
55

66
func markUsed<T>(_ t: T) {}
77

8-
markUsed(t != nil) // expected-error {{value of type 'Bool' can never be nil, comparison isn't allowed}}
9-
markUsed(f != nil) // expected-error {{value of type 'Bool' can never be nil, comparison isn't allowed}}
8+
markUsed(t != nil) // expected-error {{type 'Bool' is not optional, value can never be nil}}
9+
markUsed(f != nil) // expected-error {{type 'Bool' is not optional, value can never be nil}}
1010

1111
class C : Equatable {}
1212

@@ -15,7 +15,7 @@ func == (lhs: C, rhs: C) -> Bool {
1515
}
1616

1717
func test(_ c: C) {
18-
if c == nil {} // expected-error {{value of type 'C' can never be nil, comparison isn't allowed}}
18+
if c == nil {} // expected-error {{type 'C' is not optional, value can never be nil}}
1919
}
2020

2121
class D {}
@@ -24,6 +24,6 @@ var d = D()
2424
var dopt: D? = nil
2525
var diuopt: D! = nil
2626

27-
_ = d == nil // expected-error{{value of type 'D' can never be nil, comparison isn't allowed}}
27+
_ = d == nil // expected-error{{type 'D' is not optional, value can never be nil}}
2828
_ = dopt == nil
2929
_ = diuopt == nil

test/expr/expressions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,10 +682,10 @@ func invalidDictionaryLiteral() {
682682
//===----------------------------------------------------------------------===//
683683
// nil/metatype comparisons
684684
//===----------------------------------------------------------------------===//
685-
Int.self == nil // expected-error {{value of type 'Int.Type' can never be nil, comparison isn't allowed}}
685+
Int.self == nil // expected-error {{type 'Int.Type' is not optional, value can never be nil}}
686686
nil == Int.self // expected-error {{binary operator '==' cannot be applied to operands}}
687687
// expected-note @-1 {{overloads for '==' exist with these partially matching parameter lists}}
688-
Int.self != nil // expected-error {{value of type 'Int.Type' can never be nil, comparison isn't allowed}}
688+
Int.self != nil // expected-error {{type 'Int.Type' is not optional, value can never be nil}}
689689
nil != Int.self // expected-error {{binary operator '!=' cannot be applied to operands}}
690690
// expected-note @-1 {{overloads for '!=' exist with these partially matching parameter lists}}
691691

0 commit comments

Comments
 (0)