diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index c33e11ca5a2..d7c29e9f06b 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -1226,3 +1226,17 @@ bool AutoClosureForwardingFailure::diagnoseAsError() { .fixItInsertAfter(argExpr->getEndLoc(), "()"); return true; } + +bool NonOptionalUnwrapFailure::diagnoseAsError() { + auto *anchor = getAnchor(); + + auto diagnostic = diag::invalid_optional_chain; + if (isa(anchor)) + diagnostic = diag::invalid_force_unwrap; + + emitDiagnostic(anchor->getLoc(), diagnostic, BaseType) + .highlight(anchor->getSourceRange()) + .fixItRemove(anchor->getEndLoc()); + + return true; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 777db6d6b73..f9a3e33c6f9 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -607,6 +607,29 @@ public: bool diagnoseAsError() override; }; +/// Diagnose situations when there was an attempt to unwrap entity +/// of non-optional type e.g. +/// +/// ```swift +/// let i: Int = 0 +/// _ = i! +/// +/// struct A { func foo() {} } +/// func foo(_ a: A) { +/// a?.foo() +/// } +/// ``` +class NonOptionalUnwrapFailure final : public FailureDiagnostic { + Type BaseType; + +public: + NonOptionalUnwrapFailure(Expr *root, ConstraintSystem &cs, Type baseType, + ConstraintLocator *locator) + : FailureDiagnostic(root, cs, locator), BaseType(baseType) {} + + bool diagnoseAsError() override; +}; + } // end namespace constraints } // end namespace swift diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 0249be20efa..4b3cdd8254f 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -215,7 +215,9 @@ AutoClosureForwarding *AutoClosureForwarding::create(ConstraintSystem &cs, } bool RemoveUnwrap::diagnose(Expr *root, bool asNote) const { - return false; + auto failure = NonOptionalUnwrapFailure(root, getConstraintSystem(), BaseType, + getLocator()); + return failure.diagnose(asNote); } RemoveUnwrap *RemoveUnwrap::create(ConstraintSystem &cs, Type baseType, diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift index b1bf0f4d08f..09c4981ef77 100644 --- a/test/Constraints/diagnostics.swift +++ b/test/Constraints/diagnostics.swift @@ -1183,6 +1183,14 @@ func rdar17170728() { let _ = [i, j, k].reduce(0 as Int?) { $0 && $1 ? $0! + $1! : ($0 ? $0! : ($1 ? $1! : nil)) + // expected-error@-1 {{cannot force unwrap value of non-optional type 'Bool'}} {{18-19=}} + // expected-error@-2 {{cannot force unwrap value of non-optional type 'Bool'}} {{24-25=}} + // expected-error@-3 {{cannot force unwrap value of non-optional type 'Bool'}} {{36-37=}} + // expected-error@-4 {{cannot force unwrap value of non-optional type 'Bool'}} {{48-49=}} + } + + let _ = [i, j, k].reduce(0 as Int?) { + $0 && $1 ? $0 + $1 : ($0 ? $0 : ($1 ? $1 : nil)) // expected-error@-1 {{ambiguous use of operator '+'}} } } diff --git a/test/Constraints/dynamic_lookup.swift b/test/Constraints/dynamic_lookup.swift index 048902adf47..9888157213d 100644 --- a/test/Constraints/dynamic_lookup.swift +++ b/test/Constraints/dynamic_lookup.swift @@ -210,7 +210,6 @@ type(of: obj).foo!(obj)(5) // expected-error{{instance member 'foo' cannot be us // Checked casts to AnyObject var p: P = Y() -// expected-warning @+1 {{forced cast from 'P' to 'AnyObject' always succeeds; did you mean to use 'as'?}} var obj3 : AnyObject = (p as! AnyObject)! // expected-error{{cannot force unwrap value of non-optional type 'AnyObject'}} {{41-42=}} // Implicit force of an implicitly unwrapped optional diff --git a/test/Constraints/optional.swift b/test/Constraints/optional.swift index 1948c7d7d8e..b25577899f7 100644 --- a/test/Constraints/optional.swift +++ b/test/Constraints/optional.swift @@ -292,3 +292,13 @@ func se0213() { _ = Q("who")!.foo // Ok _ = Q?("how") // Ok } + +func rdar45218255(_ i: Int) { + struct S { + init(_:[T]) {} + } + + _ = i! // expected-error {{cannot force unwrap value of non-optional type 'Int'}} {{8-9=}} + _ = [i!] // expected-error {{cannot force unwrap value of non-optional type 'Int'}} {{9-10=}} + _ = S([i!]) // expected-error {{cannot force unwrap value of non-optional type 'Int'}} {{16-17=}} +} diff --git a/test/Parse/operators.swift b/test/Parse/operators.swift index c73bba76f4e..73694cd7fd1 100644 --- a/test/Parse/operators.swift +++ b/test/Parse/operators.swift @@ -116,8 +116,11 @@ infix operator !! func !!(x: Man, y: Man) {} let foo = Man() let bar = TheDevil() -foo!!foo // expected-error{{cannot force unwrap value of non-optional type 'Man'}} {{4-5=}} expected-error{{consecutive statements}} {{6-6=;}} -// expected-warning @-1 {{expression of type 'Man' is unused}} +foo!!foo +// expected-error@-1 {{cannot force unwrap value of non-optional type 'Man'}} {{4-5=}} +// expected-error@-2 {{cannot force unwrap value of non-optional type 'Man'}} {{5-6=}} +// expected-error@-3 {{consecutive statements}} {{6-6=;}} +// expected-warning@-4 {{expression of type 'Man' is unused}} foo??bar // expected-error{{broken standard library}} expected-error{{consecutive statements}} {{6-6=;}} // expected-warning @-1 {{expression of type 'TheDevil' is unused}} diff --git a/test/decl/init/failable.swift b/test/decl/init/failable.swift index d93e4396c13..d678ff8e724 100644 --- a/test/decl/init/failable.swift +++ b/test/decl/init/failable.swift @@ -60,7 +60,7 @@ class Sub : Super { } convenience init(forceNonfail: Int) { - self.init(nonfail: forceNonfail)! // expected-error{{cannot force unwrap value of non-optional type '()'}} {{37-38=}} + self.init(nonfail: forceNonfail)! // expected-error{{cannot force unwrap value of non-optional type 'Sub'}} {{37-38=}} } init(nonfail2: Int) { // okay, traps on nil