Revert "Combine the two diagnostics"

This reverts commit 2e7656218e.
This commit is contained in:
Cal Stephens
2022-09-01 08:11:46 -07:00
parent 568549f2c3
commit c2bf0f943e
6 changed files with 71 additions and 61 deletions

View File

@@ -4007,7 +4007,10 @@ WARNING(use_of_qq_on_non_optional_value,none,
"left side of nil coalescing operator '?""?' has non-optional type %0, "
"so the right side is never used", (Type))
WARNING(nonoptional_compare_to_nil,none,
"comparing non-optional value of type %0 to 'nil' or 'Optional.none' always returns"
"comparing non-optional value of type %0 to 'nil' always returns"
" %select{false|true}1", (Type, bool))
WARNING(nonoptional_compare_to_optional_none_case,none,
"comparing non-optional value of type %0 to 'Optional.none' always returns"
" %select{false|true}1", (Type, bool))
WARNING(optional_check_nonoptional,none,
"non-optional expression of type %0 used in a check for optionals",

View File

@@ -1282,28 +1282,19 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
}
/// Return true if this is a 'nil' literal. This looks
/// like this if the type is Optional<T>:
///
/// (dot_syntax_call_expr type='String?'
/// (declref_expr type='(Optional<String>.Type) -> Optional<String>'
/// decl=Swift.(file).Optional.none function_ref=unapplied)
/// (argument_list implicit
/// (argument
/// (type_expr implicit type='String?.Type' typerepr='String?'))))
///
/// Or like this if it is any other ExpressibleByNilLiteral type:
///
/// (nil_literal_expr)
///
bool isTypeCheckedOptionalNil(Expr *E) {
/// Returns true if this is a 'nil' literal
bool isNilLiteral(Expr *E) {
if (dyn_cast<NilLiteralExpr>(E)) return true;
return false;
}
/// Returns true if this is a expression is a reference to
/// the `Optional.none` case specifically (e.g. not `nil`).
bool isOptionalNoneCase(Expr *E) {
auto CE = dyn_cast<ApplyExpr>(E->getSemanticsProvidingExpr());
if (!CE)
return false;
// First case -- Optional.none
if (auto DRE = dyn_cast<DeclRefExpr>(CE->getSemanticFn()))
return DRE->getDecl() == Ctx.getOptionalNoneDecl();
@@ -1348,9 +1339,12 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
if (calleeName == "==" || calleeName == "!=" ||
calleeName == "===" || calleeName == "!==") {
bool isTrue = calleeName == "!=" || calleeName == "!==";
// Diagnose a redundant comparison of a non-optional to a `nil` literal
if (((subExpr = isImplicitPromotionToOptional(lhs)) &&
isTypeCheckedOptionalNil(rhs)) ||
(isTypeCheckedOptionalNil(lhs) &&
isNilLiteral(rhs)) ||
(isNilLiteral(lhs) &&
(subExpr = isImplicitPromotionToOptional(rhs)))) {
bool isTrue = calleeName == "!=" || calleeName == "!==";
@@ -1360,6 +1354,19 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
.highlight(rhs->getSourceRange());
return;
}
// Diagnose a redundant comparison of a non-optional to the `Optional.none` case
if (((subExpr = isImplicitPromotionToOptional(lhs)) &&
isOptionalNoneCase(rhs)) ||
(isOptionalNoneCase(lhs) &&
(subExpr = isImplicitPromotionToOptional(rhs)))) {
Ctx.Diags.diagnose(DRE->getLoc(), diag::nonoptional_compare_to_optional_none_case,
subExpr->getType(), isTrue)
.highlight(lhs->getSourceRange())
.highlight(rhs->getSourceRange());
return;
}
}
}
};

View File

@@ -5,12 +5,12 @@ import CoreCooling
func testSomeClass(_ sc: SomeClass, osc: SomeClass?) {
let ao1: Any = sc.methodA(osc)
_ = ao1
if sc.methodA(osc) == nil { } // expected-warning {{comparing non-optional value of type 'Any' to 'nil' or 'Optional.none' always returns false}}
if sc.methodA(osc) == Optional.none { } // expected-warning {{comparing non-optional value of type 'Any' to 'nil' or 'Optional.none' always returns false}}
if sc.methodA(osc) == nil { } // expected-warning {{comparing non-optional value of type 'Any' to 'nil' always returns false}}
if sc.methodA(osc) == Optional.none { } // expected-warning {{comparing non-optional value of type 'Any' to 'Optional.none' always returns false}}
let ao2: Any = sc.methodB(nil)
_ = ao2
if sc.methodA(osc) == nil { }// expected-warning {{comparing non-optional value of type 'Any' to 'nil' or 'Optional.none' always returns false}}
if sc.methodA(osc) == nil { }// expected-warning {{comparing non-optional value of type 'Any' to 'nil' always returns false}}
let ao3: Any? = sc.property.flatMap { .some($0) }
_ = ao3
@@ -19,7 +19,7 @@ func testSomeClass(_ sc: SomeClass, osc: SomeClass?) {
let ao4: Any = sc.methodD()
_ = ao4
if sc.methodD() == nil { } // expected-warning {{comparing non-optional value of type 'Any' to 'nil' or 'Optional.none' always returns false}}
if sc.methodD() == nil { } // expected-warning {{comparing non-optional value of type 'Any' to 'nil' always returns false}}
sc.methodE(sc)
sc.methodE(osc) // expected-error{{value of optional type 'SomeClass?' must be unwrapped}}
@@ -44,7 +44,7 @@ func testSomeClass(_ sc: SomeClass, osc: SomeClass?) {
let sc2 = SomeClass(int: ci)
let sc2a: SomeClass = sc2
_ = sc2a
if sc2 == nil { } // expected-warning {{comparing non-optional value of type 'SomeClass' to 'nil' or 'Optional.none' always returns false}}
if sc2 == nil { } // expected-warning {{comparing non-optional value of type 'SomeClass' to 'nil' always returns false}}
let sc3 = SomeClass(double: 1.5)
if sc3 == nil { } // okay
@@ -56,7 +56,7 @@ func testSomeClass(_ sc: SomeClass, osc: SomeClass?) {
let sc4 = sc.returnMe()
let sc4a: SomeClass = sc4
_ = sc4a
if sc4 == nil { } // expected-warning {{comparing non-optional value of type 'SomeClass' to 'nil' or 'Optional.none' always returns false}}
if sc4 == nil { } // expected-warning {{comparing non-optional value of type 'SomeClass' to 'nil' always returns false}}
}
// Nullability with CF types.

View File

@@ -222,7 +222,7 @@ class r20201968C {
// <rdar://problem/21459429> QoI: Poor compilation error calling assert
func r21459429(_ a : Int) {
assert(a != nil, "ASSERT COMPILATION ERROR")
// expected-warning @-1 {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns true}}
// expected-warning @-1 {{comparing non-optional value of type 'Int' to 'nil' always returns true}}
}
@@ -537,7 +537,7 @@ func r21684487() {
func r18397777(_ d : r21447318?) {
let c = r21447318()
if c != nil { // expected-warning {{comparing non-optional value of type 'r21447318' to 'nil' or 'Optional.none' always returns true}}
if c != nil { // expected-warning {{comparing non-optional value of type 'r21447318' to 'nil' always returns true}}
}
if d { // expected-error {{optional type 'r21447318?' cannot be used as a boolean; test for '!= nil' instead}} {{6-6=(}} {{7-7= != nil)}}
@@ -745,27 +745,27 @@ class C_44203 {
func f(bytes : UnsafeMutablePointer<Int>, _ i : Int?) {
_ = (i === nil) // expected-error {{value of type 'Int?' cannot be compared by reference; did you mean to compare by value?}} {{12-15===}}
_ = (bytes === nil) // expected-error {{type 'UnsafeMutablePointer<Int>' is not optional, value can never be nil}}
_ = (self === nil) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns false}}
_ = (self === .none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns false}}
_ = (self === Optional.none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns false}}
_ = (self === nil) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' always returns false}}
_ = (self === .none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'Optional.none' always returns false}}
_ = (self === Optional.none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'Optional.none' always returns false}}
_ = (i !== nil) // expected-error {{value of type 'Int?' cannot be compared by reference; did you mean to compare by value?}} {{12-15=!=}}
_ = (bytes !== nil) // expected-error {{type 'UnsafeMutablePointer<Int>' is not optional, value can never be nil}}
_ = (self !== nil) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns true}}
_ = (self !== .none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns true}}
_ = (self !== Optional.none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns true}}
_ = (self !== nil) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' always returns true}}
_ = (self !== .none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'Optional.none' always returns true}}
_ = (self !== Optional.none) // expected-warning {{comparing non-optional value of type 'AnyObject' to 'Optional.none' always returns true}}
}
}
func nilComparison(i: Int, o: AnyObject) {
_ = i == nil // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns false}}
_ = nil == i // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns false}}
_ = i != nil // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns true}}
_ = nil != i // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns true}}
_ = i == nil // expected-warning {{comparing non-optional value of type 'Int' to 'nil' always returns false}}
_ = nil == i // expected-warning {{comparing non-optional value of type 'Int' to 'nil' always returns false}}
_ = i != nil // expected-warning {{comparing non-optional value of type 'Int' to 'nil' always returns true}}
_ = nil != i // expected-warning {{comparing non-optional value of type 'Int' to 'nil' always returns true}}
_ = i == Optional.none // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns false}}
_ = Optional.none == i // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns false}}
_ = i != Optional.none // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns true}}
_ = Optional.none != i // expected-warning {{comparing non-optional value of type 'Int' to 'nil' or 'Optional.none' always returns true}}
_ = i == Optional.none // expected-warning {{comparing non-optional value of type 'Int' to 'Optional.none' always returns false}}
_ = Optional.none == i // expected-warning {{comparing non-optional value of type 'Int' to 'Optional.none' always returns false}}
_ = i != Optional.none // expected-warning {{comparing non-optional value of type 'Int' to 'Optional.none' always returns true}}
_ = Optional.none != i // expected-warning {{comparing non-optional value of type 'Int' to 'Optional.none' always returns true}}
// FIXME(integers): uncomment these tests once the < is no longer ambiguous
// _ = i < nil // _xpected-error {{type 'Int' is not optional, value can never be nil}}
@@ -777,8 +777,8 @@ func nilComparison(i: Int, o: AnyObject) {
// _ = i >= nil // _xpected-error {{type 'Int' is not optional, value can never be nil}}
// _ = nil >= i // _xpected-error {{type 'Int' is not optional, value can never be nil}}
_ = o === nil // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns false}}
_ = o !== nil // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' or 'Optional.none' always returns true}}
_ = o === nil // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' always returns false}}
_ = o !== nil // expected-warning {{comparing non-optional value of type 'AnyObject' to 'nil' always returns true}}
}
// <rdar://problem/23709100> QoI: incorrect ambiguity error due to implicit conversion

View File

@@ -5,10 +5,10 @@ var f = false
func markUsed<T>(_ t: T) {}
markUsed(t != nil) // expected-warning {{comparing non-optional value of type 'Bool' to 'nil' or 'Optional.none' always returns true}}
markUsed(f != nil) // expected-warning {{comparing non-optional value of type 'Bool' to 'nil' or 'Optional.none' always returns true}}
markUsed(t != Optional.none) // expected-warning {{comparing non-optional value of type 'Bool' to 'nil' or 'Optional.none' always returns true}}
markUsed(f != Optional.none) // expected-warning {{comparing non-optional value of type 'Bool' to 'nil' or 'Optional.none' always returns true}}
markUsed(t != nil) // expected-warning {{comparing non-optional value of type 'Bool' to 'nil' always returns true}}
markUsed(f != nil) // expected-warning {{comparing non-optional value of type 'Bool' to 'nil' always returns true}}
markUsed(t != Optional.none) // expected-warning {{comparing non-optional value of type 'Bool' to 'Optional.none' always returns true}}
markUsed(f != Optional.none) // expected-warning {{comparing non-optional value of type 'Bool' to 'Optional.none' always returns true}}
class C : Equatable {}
@@ -17,10 +17,10 @@ func == (lhs: C, rhs: C) -> Bool {
}
func test(_ c: C) {
if c == nil {} // expected-warning {{comparing non-optional value of type 'C' to 'nil' or 'Optional.none' always returns false}}
if c == .none {} // expected-warning {{comparing non-optional value of type 'C' to 'nil' or 'Optional.none' always returns false}}
if c == Optional.none {} // expected-warning {{comparing non-optional value of type 'C' to 'nil' or 'Optional.none' always returns false}}
if c == C?.none {} // expected-warning {{comparing non-optional value of type 'C' to 'nil' or 'Optional.none' always returns false}}
if c == nil {} // expected-warning {{comparing non-optional value of type 'C' to 'nil' always returns false}}
if c == .none {} // expected-warning {{comparing non-optional value of type 'C' to 'Optional.none' always returns false}}
if c == Optional.none {} // expected-warning {{comparing non-optional value of type 'C' to 'Optional.none' always returns false}}
if c == C?.none {} // expected-warning {{comparing non-optional value of type 'C' to 'Optional.none' always returns false}}
}
class D {}
@@ -44,4 +44,4 @@ func test(_ e: E) {
_ = e == E.none
_ = e == Optional.none // expected-warning {{comparing non-optional value of type 'E' to 'nil' or 'Optional.none' always returns false}}
_ = e == E?.none // expected-warning {{comparing non-optional value of type 'E' to 'nil' or 'Optional.none' always returns false}}
}
}

View File

@@ -762,15 +762,15 @@ func invalidDictionaryLiteral() {
//===----------------------------------------------------------------------===//
// nil/metatype comparisons
//===----------------------------------------------------------------------===//
_ = Int.self == nil // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns false}}
_ = nil == Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns false}}
_ = Int.self != nil // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns true}}
_ = nil != Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns true}}
_ = Int.self == nil // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' always returns false}}
_ = nil == Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' always returns false}}
_ = Int.self != nil // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' always returns true}}
_ = nil != Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' always returns true}}
_ = Int.self == .none // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns false}}
_ = .none == Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns false}}
_ = Int.self != .none // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns true}}
_ = .none != Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'nil' or 'Optional.none' always returns true}}
_ = Int.self == .none // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'Optional.none' always returns false}}
_ = .none == Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'Optional.none' always returns false}}
_ = Int.self != .none // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'Optional.none' always returns true}}
_ = .none != Int.self // expected-warning {{comparing non-optional value of type 'any Any.Type' to 'Optional.none' always returns true}}
// <rdar://problem/19032294> Disallow postfix ? when not chaining
func testOptionalChaining(_ a : Int?, b : Int!, c : Int??) {