mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
521 lines
14 KiB
Swift
521 lines
14 KiB
Swift
// RUN: %target-typecheck-verify-swift
|
|
|
|
/* block comments */
|
|
/* /* nested too */ */
|
|
|
|
func markUsed<T>(_ t: T) {}
|
|
|
|
func f1(_ a: Int, _ y: Int) {}
|
|
func f2() {}
|
|
func f3() -> Int {}
|
|
|
|
func invalid_semi() {
|
|
; // expected-error {{';' statements are not allowed}} {{3-5=}}
|
|
}
|
|
|
|
func nested1(_ x: Int) {
|
|
var y : Int
|
|
|
|
func nested2(_ z: Int) -> Int {
|
|
return x+y+z
|
|
}
|
|
|
|
_ = nested2(1)
|
|
}
|
|
|
|
func funcdecl5(_ a: Int, y: Int) {
|
|
var x : Int
|
|
|
|
// a few statements
|
|
if (x != 0) {
|
|
if (x != 0 || f3() != 0) {
|
|
// while with and without a space after it.
|
|
while(true) { 4; 2; 1 } // expected-warning 3 {{integer literal is unused}}
|
|
while (true) { 4; 2; 1 } // expected-warning 3 {{integer literal is unused}}
|
|
}
|
|
}
|
|
|
|
// Assignment statement.
|
|
x = y
|
|
(x) = y
|
|
|
|
1 = x // expected-error {{cannot assign to a literal value}}
|
|
(1) = x // expected-error {{cannot assign to a literal value}}
|
|
(x:1).x = 1 // expected-error {{cannot assign to immutable expression of type 'Int'}}
|
|
var tup : (x:Int, y:Int)
|
|
tup.x = 1
|
|
_ = tup
|
|
|
|
let B : Bool
|
|
|
|
// if/then/else.
|
|
if (B) {
|
|
} else if (y == 2) {
|
|
}
|
|
|
|
// This diagnostic is terrible - rdar://12939553
|
|
if x {} // expected-error {{'Int' is not convertible to 'Bool'}}
|
|
|
|
if true {
|
|
if (B) {
|
|
} else {
|
|
}
|
|
}
|
|
|
|
if (B) {
|
|
f1(1,2)
|
|
} else {
|
|
f2()
|
|
}
|
|
|
|
if (B) {
|
|
if (B) {
|
|
f1(1,2)
|
|
} else {
|
|
f2()
|
|
}
|
|
} else {
|
|
f2()
|
|
}
|
|
|
|
// while statement.
|
|
while (B) {
|
|
}
|
|
|
|
// It's okay to leave out the spaces in these.
|
|
while(B) {}
|
|
if(B) {}
|
|
}
|
|
|
|
struct infloopbool {
|
|
var boolValue: infloopbool {
|
|
return self
|
|
}
|
|
}
|
|
|
|
func infloopbooltest() {
|
|
if (infloopbool()) {} // expected-error {{'infloopbool' is not convertible to 'Bool'}}
|
|
}
|
|
|
|
// test "builder" API style
|
|
extension Int {
|
|
static func builder() -> Int { }
|
|
var builderProp: Int { return 0 }
|
|
func builder2() {}
|
|
}
|
|
Int
|
|
.builder()
|
|
.builderProp
|
|
.builder2()
|
|
|
|
struct SomeGeneric<T> {
|
|
static func builder() -> SomeGeneric<T> { }
|
|
var builderProp: SomeGeneric<T> { return .builder() }
|
|
func builder2() {}
|
|
}
|
|
SomeGeneric<Int>
|
|
.builder()
|
|
.builderProp
|
|
.builder2()
|
|
|
|
|
|
break // expected-error {{'break' is only allowed inside a loop, if, do, or switch}}
|
|
continue // expected-error {{'continue' is only allowed inside a loop}}
|
|
while true {
|
|
func f() {
|
|
break // expected-error {{'break' is only allowed inside a loop}}
|
|
continue // expected-error {{'continue' is only allowed inside a loop}}
|
|
}
|
|
|
|
// Labeled if
|
|
MyIf: if 1 != 2 {
|
|
break MyIf
|
|
continue MyIf // expected-error {{'continue' cannot be used with if statements}}
|
|
break // break the while
|
|
continue // continue the while.
|
|
}
|
|
}
|
|
|
|
// Labeled if
|
|
MyOtherIf: if 1 != 2 {
|
|
break MyOtherIf
|
|
continue MyOtherIf // expected-error {{'continue' cannot be used with if statements}}
|
|
break // expected-error {{unlabeled 'break' is only allowed inside a loop or switch, a labeled break is required to exit an if}}
|
|
continue // expected-error {{'continue' is only allowed inside a loop}}
|
|
}
|
|
|
|
do {
|
|
break // expected-error {{unlabeled 'break' is only allowed inside a loop or switch, a labeled break is required to exit an if or do}}
|
|
}
|
|
|
|
func tuple_assign() {
|
|
var a,b,c,d : Int
|
|
(a,b) = (1,2)
|
|
func f() -> (Int,Int) { return (1,2) }
|
|
((a,b), (c,d)) = (f(), f())
|
|
}
|
|
|
|
func missing_semicolons() {
|
|
var w = 321
|
|
func g() {}
|
|
g() w += 1 // expected-error{{consecutive statements}} {{6-6=;}}
|
|
var z = w"hello" // expected-error{{consecutive statements}} {{12-12=;}} expected-warning {{string literal is unused}}
|
|
class C {}class C2 {} // expected-error{{consecutive statements}} {{14-14=;}}
|
|
struct S {}struct S2 {} // expected-error{{consecutive statements}} {{14-14=;}}
|
|
func j() {}func k() {} // expected-error{{consecutive statements}} {{14-14=;}}
|
|
}
|
|
|
|
//===--- Return statement.
|
|
|
|
return 42 // expected-error {{return invalid outside of a func}}
|
|
|
|
return // expected-error {{return invalid outside of a func}}
|
|
|
|
func NonVoidReturn1() -> Int {
|
|
return // expected-error {{non-void function should return a value}}
|
|
}
|
|
|
|
func NonVoidReturn2() -> Int {
|
|
return + // expected-error {{unary operator cannot be separated from its operand}} {{11-1=}} expected-error {{expected expression in 'return' statement}}
|
|
}
|
|
|
|
func VoidReturn1() {
|
|
if true { return }
|
|
// Semicolon should be accepted -- rdar://11344875
|
|
return; // no-error
|
|
}
|
|
|
|
func VoidReturn2() {
|
|
return () // no-error
|
|
}
|
|
|
|
func VoidReturn3() {
|
|
return VoidReturn2() // no-error
|
|
}
|
|
|
|
//===--- If statement.
|
|
|
|
func IfStmt1() {
|
|
if 1 > 0 // expected-error {{expected '{' after 'if' condition}}
|
|
_ = 42
|
|
}
|
|
|
|
func IfStmt2() {
|
|
if 1 > 0 {
|
|
} else // expected-error {{expected '{' after 'else'}}
|
|
_ = 42
|
|
}
|
|
|
|
//===--- While statement.
|
|
|
|
func WhileStmt1() {
|
|
while 1 > 0 // expected-error {{expected '{' after 'while' condition}}
|
|
_ = 42
|
|
}
|
|
|
|
//===-- Do statement.
|
|
func DoStmt() {
|
|
// This is just a 'do' statement now.
|
|
do {
|
|
}
|
|
}
|
|
|
|
func DoWhileStmt() {
|
|
do { // expected-error {{'do-while' statement is not allowed; use 'repeat-while' instead}} {{3-5=repeat}}
|
|
} while true
|
|
}
|
|
|
|
//===--- Repeat-while statement.
|
|
|
|
func RepeatWhileStmt1() {
|
|
repeat {} while true
|
|
|
|
repeat {} while false
|
|
|
|
repeat { break } while true
|
|
repeat { continue } while true
|
|
}
|
|
|
|
func RepeatWhileStmt2() {
|
|
repeat // expected-error {{expected '{' after 'repeat'}} expected-error {{expected 'while' after body of 'repeat' statement}}
|
|
}
|
|
|
|
func RepeatWhileStmt4() {
|
|
repeat {
|
|
} while + // expected-error {{unary operator cannot be separated from its operand}} {{12-1=}} expected-error {{expected expression in 'repeat-while' condition}}
|
|
}
|
|
|
|
func brokenSwitch(_ x: Int) -> Int {
|
|
switch x {
|
|
case .Blah(var rep): // expected-error{{pattern cannot match values of type 'Int'}}
|
|
return rep
|
|
}
|
|
}
|
|
|
|
func switchWithVarsNotMatchingTypes(_ x: Int, y: Int, z: String) -> Int {
|
|
switch (x,y,z) {
|
|
case (let a, 0, _), (0, let a, _): // OK
|
|
return a
|
|
case (let a, _, _), (_, _, let a): // expected-error {{pattern variable bound to type 'String', expected type 'Int'}}
|
|
// expected-warning@-1 {{case is already handled by previous patterns; consider removing it}}
|
|
return a
|
|
}
|
|
}
|
|
|
|
func breakContinue(_ x : Int) -> Int {
|
|
|
|
Outer:
|
|
for _ in 0...1000 {
|
|
|
|
Switch: // expected-error {{switch must be exhaustive}} expected-note{{do you want to add a default clause?}}
|
|
switch x {
|
|
case 42: break Outer
|
|
case 97: continue Outer
|
|
case 102: break Switch
|
|
case 13: continue
|
|
case 139: break // <rdar://problem/16563853> 'break' should be able to break out of switch statements
|
|
}
|
|
}
|
|
|
|
// <rdar://problem/16692437> shadowing loop labels should be an error
|
|
Loop: // expected-note {{previously declared here}}
|
|
for _ in 0...2 {
|
|
Loop: // expected-error {{label 'Loop' cannot be reused on an inner statement}}
|
|
for _ in 0...2 {
|
|
}
|
|
}
|
|
|
|
|
|
// <rdar://problem/16798323> Following a 'break' statement by another statement on a new line result in an error/fit-it
|
|
switch 5 {
|
|
case 5:
|
|
markUsed("before the break")
|
|
break
|
|
markUsed("after the break") // 'markUsed' is not a label for the break.
|
|
default:
|
|
markUsed("")
|
|
}
|
|
|
|
let x : Int? = 42
|
|
|
|
// <rdar://problem/16879701> Should be able to pattern match 'nil' against optionals
|
|
switch x { // expected-error {{switch must be exhaustive}}
|
|
// expected-note@-1 {{missing case: '.some(_)'}}
|
|
case .some(42): break
|
|
case nil: break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
enum MyEnumWithCaseLabels {
|
|
case Case(one: String, two: Int)
|
|
}
|
|
|
|
func testMyEnumWithCaseLabels(_ a : MyEnumWithCaseLabels) {
|
|
// <rdar://problem/20135489> Enum case labels are ignored in "case let" statements
|
|
switch a {
|
|
case let .Case(one: _, two: x): break // ok
|
|
case let .Case(xxx: _, two: x): break // expected-error {{tuple pattern element label 'xxx' must be 'one'}}
|
|
// TODO: In principle, reordering like this could be supported.
|
|
case let .Case(two: _, one: x): break // expected-error {{tuple pattern element label}}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// "defer"
|
|
|
|
func test_defer(_ a : Int) {
|
|
|
|
defer { VoidReturn1() }
|
|
defer { breakContinue(1)+42 } // expected-warning {{result of operator '+' is unused}}
|
|
|
|
// Ok:
|
|
defer { while false { break } }
|
|
|
|
// Not ok.
|
|
while false { defer { break } } // expected-error {{'break' cannot transfer control out of a defer statement}}
|
|
defer { return } // expected-error {{'return' cannot transfer control out of a defer statement}}
|
|
}
|
|
|
|
class SomeTestClass {
|
|
var x = 42
|
|
|
|
func method() {
|
|
defer { x = 97 } // self. not required here!
|
|
}
|
|
}
|
|
|
|
class SomeDerivedClass: SomeTestClass {
|
|
override init() {
|
|
defer {
|
|
super.init() // expected-error {{initializer chaining ('super.init') cannot be nested in another expression}}
|
|
}
|
|
}
|
|
}
|
|
|
|
func test_guard(_ x : Int, y : Int??, cond : Bool) {
|
|
|
|
// These are all ok.
|
|
guard let a = y else {}
|
|
markUsed(a)
|
|
guard let b = y, cond else {}
|
|
guard case let c = x, cond else {}
|
|
guard case let Optional.some(d) = y else {}
|
|
guard x != 4, case _ = x else { }
|
|
|
|
|
|
guard let e, cond else {} // expected-error {{variable binding in a condition requires an initializer}}
|
|
guard case let f? : Int?, cond else {} // expected-error {{variable binding in a condition requires an initializer}}
|
|
|
|
guard let g = y else {
|
|
markUsed(g) // expected-error {{variable declared in 'guard' condition is not usable in its body}}
|
|
}
|
|
|
|
guard let h = y, cond {} // expected-error {{expected 'else' after 'guard' condition}} {{25-25=else }}
|
|
|
|
|
|
guard case _ = x else {} // expected-warning {{'guard' condition is always true, body is unreachable}}
|
|
}
|
|
|
|
func test_is_as_patterns() {
|
|
switch 4 {
|
|
case is Int: break // expected-warning {{'is' test is always true}}
|
|
case _ as Int: break // expected-warning {{'as' test is always true}}
|
|
// expected-warning@-1 {{case is already handled by previous patterns; consider removing it}}
|
|
case _: break // expected-warning {{case is already handled by previous patterns; consider removing it}}
|
|
}
|
|
}
|
|
|
|
// <rdar://problem/21387308> Fuzzing SourceKit: crash in Parser::parseStmtForEach(...)
|
|
func matching_pattern_recursion() {
|
|
switch 42 {
|
|
case { // expected-error {{expression pattern of type '() -> ()' cannot match values of type 'Int'}}
|
|
for i in zs {
|
|
}
|
|
}: break
|
|
}
|
|
}
|
|
|
|
// <rdar://problem/18776073> Swift's break operator in switch should be indicated in errors
|
|
func r18776073(_ a : Int?) {
|
|
switch a {
|
|
case nil: // expected-error {{'case' label in a 'switch' should have at least one executable statement}} {{14-14= break}}
|
|
case _?: break
|
|
}
|
|
}
|
|
|
|
// <rdar://problem/22491782> unhelpful error message from "throw nil"
|
|
func testThrowNil() throws {
|
|
throw nil // expected-error {{cannot infer concrete Error for thrown 'nil' value}}
|
|
}
|
|
|
|
|
|
// rdar://problem/23684220
|
|
// Even if the condition fails to typecheck, save it in the AST anyway; the old
|
|
// condition may have contained a SequenceExpr.
|
|
func r23684220(_ b: Any) {
|
|
if let _ = b ?? b {} // expected-error {{initializer for conditional binding must have Optional type, not 'Any'}}
|
|
// expected-warning@-1 {{left side of nil coalescing operator '??' has non-optional type 'Any', so the right side is never used}}
|
|
}
|
|
|
|
|
|
// <rdar://problem/21080671> QoI: try/catch (instead of do/catch) creates silly diagnostics
|
|
func f21080671() {
|
|
try { // expected-error {{the 'do' keyword is used to specify a 'catch' region}} {{3-6=do}}
|
|
} catch { }
|
|
|
|
|
|
try { // expected-error {{the 'do' keyword is used to specify a 'catch' region}} {{3-6=do}}
|
|
f21080671()
|
|
} catch let x as Int {
|
|
} catch {
|
|
}
|
|
}
|
|
|
|
// <rdar://problem/24467411> QoI: Using "&& #available" should fixit to comma
|
|
// https://twitter.com/radexp/status/694561060230184960
|
|
func f(_ x : Int, y : Int) {
|
|
if x == y && #available(iOS 52, *) {} // expected-error {{expected ',' joining parts of a multi-clause condition}} {{12-15=,}}
|
|
if #available(iOS 52, *) && x == y {} // expected-error {{expected ',' joining parts of a multi-clause condition}} {{27-30=,}}
|
|
|
|
// https://twitter.com/radexp/status/694790631881883648
|
|
if x == y && let _ = Optional(y) {} // expected-error {{expected ',' joining parts of a multi-clause condition}} {{12-15=,}}
|
|
if x == y&&let _ = Optional(y) {} // expected-error {{expected ',' joining parts of a multi-clause condition}} {{12-14=,}}
|
|
}
|
|
|
|
|
|
|
|
// <rdar://problem/25178926> QoI: Warn about cases where switch statement "ignores" where clause
|
|
enum Type {
|
|
case Foo
|
|
case Bar
|
|
}
|
|
func r25178926(_ a : Type) {
|
|
switch a { // expected-error {{switch must be exhaustive}}
|
|
// expected-note@-1 {{missing case: '.Bar'}}
|
|
case .Foo, .Bar where 1 != 100:
|
|
// expected-warning @-1 {{'where' only applies to the second pattern match in this case}}
|
|
// expected-note @-2 {{disambiguate by adding a line break between them if this is desired}} {{14-14=\n }}
|
|
// expected-note @-3 {{duplicate the 'where' on both patterns to check both patterns}} {{12-12= where 1 != 100}}
|
|
break
|
|
}
|
|
|
|
switch a { // expected-error {{switch must be exhaustive}}
|
|
// expected-note@-1 {{missing case: '.Bar'}}
|
|
case .Foo: break
|
|
case .Bar where 1 != 100: break
|
|
}
|
|
|
|
switch a { // expected-error {{switch must be exhaustive}}
|
|
// expected-note@-1 {{missing case: '.Bar'}}
|
|
case .Foo, // no warn
|
|
.Bar where 1 != 100:
|
|
break
|
|
}
|
|
|
|
switch a { // expected-error {{switch must be exhaustive}}
|
|
// expected-note@-1 {{missing case: '.Foo'}}
|
|
// expected-note@-2 {{missing case: '.Bar'}}
|
|
case .Foo where 1 != 100, .Bar where 1 != 100:
|
|
break
|
|
}
|
|
}
|
|
|
|
do {
|
|
guard 1 == 2 else {
|
|
break // expected-error {{unlabeled 'break' is only allowed inside a loop or switch, a labeled break is required to exit an if or do}}
|
|
}
|
|
}
|
|
|
|
func fn(a: Int) {
|
|
guard a < 1 else {
|
|
break // expected-error {{'break' is only allowed inside a loop, if, do, or switch}}
|
|
}
|
|
}
|
|
|
|
func fn(x: Int) {
|
|
if x >= 0 {
|
|
guard x < 1 else {
|
|
guard x < 2 else {
|
|
break // expected-error {{unlabeled 'break' is only allowed inside a loop or switch, a labeled break is required to exit an if or do}}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func bad_if() {
|
|
if 1 {} // expected-error {{'Int' is not convertible to 'Bool'}}
|
|
if (x: false) {} // expected-error {{'(x: Bool)' is not convertible to 'Bool'}}
|
|
if (x: 1) {} // expected-error {{'(x: Int)' is not convertible to 'Bool'}}
|
|
}
|
|
|
|
// Errors in case syntax
|
|
class
|
|
case, // expected-error {{expected identifier in enum 'case' declaration}} expected-error {{expected pattern}}
|
|
case // expected-error {{expected identifier after comma in enum 'case' declaration}} expected-error {{expected identifier in enum 'case' declaration}} expected-error {{enum 'case' is not allowed outside of an enum}} expected-error {{expected pattern}}
|
|
// NOTE: EOF is important here to properly test a code path that used to crash the parser
|