use expect_test::expect; use super::{check_infer_with_mismatches, check_no_mismatches, check_types}; #[test] fn infer_never1() { check_types( r#" fn test() { let t = return; t; } //^ ! "#, ); } #[test] fn infer_never2() { check_types( r#" fn gen() -> T { loop {} } fn test() { let a = gen(); if false { a } else { loop {} }; a; } //^ ! "#, ); } #[test] fn infer_never3() { check_types( r#" fn gen() -> T { loop {} } fn test() { let a = gen(); if false { loop {} } else { a }; a; //^ ! } "#, ); } #[test] fn never_type_in_generic_args() { check_types( r#" enum Option { None, Some(T) } fn test() { let a = if true { Option::None } else { Option::Some(return) }; a; } //^ Option "#, ); } #[test] fn never_type_can_be_reinferred1() { check_types( r#" fn gen() -> T { loop {} } fn test() { let a = gen(); if false { loop {} } else { a }; a; //^ () if false { a }; } "#, ); } #[test] fn never_type_can_be_reinferred2() { check_types( r#" enum Option { None, Some(T) } fn test() { let a = if true { Option::None } else { Option::Some(return) }; a; //^ Option match 42 { 42 => a, _ => Option::Some(42), }; } "#, ); } #[test] fn never_type_can_be_reinferred3() { check_types( r#" enum Option { None, Some(T) } fn test() { let a = if true { Option::None } else { Option::Some(return) }; a; //^ Option<&'? str> match 42 { 42 => a, _ => Option::Some("str"), }; } "#, ); } #[test] fn match_no_arm() { check_types( r#" enum Void {} fn test(a: Void) { let t = match a {}; t; } //^ ! "#, ); } #[test] fn match_unknown_arm() { check_types( r#" fn test(a: Option) { let t = match 0 { _ => unknown, }; t; } //^ {unknown} "#, ); } #[test] fn if_never() { check_types( r#" fn test() { let i = if true { loop {} } else { 3.0 }; i; } //^ f64 "#, ); } #[test] fn if_else_never() { check_types( r#" fn test(input: bool) { let i = if input { 2.0 } else { return }; i; } //^ f64 "#, ); } #[test] fn match_first_arm_never() { check_types( r#" fn test(a: i32) { let i = match a { 1 => return, 2 => 2.0, 3 => loop {}, _ => 3.0, }; i; } //^ f64 "#, ); } #[test] fn match_second_arm_never() { check_types( r#" fn test(a: i32) { let i = match a { 1 => 3.0, 2 => loop {}, 3 => 3.0, _ => return, }; i; } //^ f64 "#, ); } #[test] fn match_all_arms_never() { check_types( r#" fn test(a: i32) { let i = match a { 2 => return, _ => loop {}, }; i; } //^ ! "#, ); } #[test] fn match_no_never_arms() { check_types( r#" fn test(a: i32) { let i = match a { 2 => 2.0, _ => 3.0, }; i; } //^ f64 "#, ); } #[test] fn diverging_expression_1() { check_infer_with_mismatches( r" //- /main.rs fn test1() { let x: u32 = return; } fn test2() { let x: u32 = { return; }; } fn test3() { let x: u32 = loop {}; } fn test4() { let x: u32 = { loop {} }; } fn test5() { let x: u32 = { if true { loop {}; } else { loop {}; } }; } fn test6() { let x: u32 = { let y: u32 = { loop {}; }; }; } ", expect![[r" 11..39 '{ ...urn; }': () 21..22 'x': u32 30..36 'return': ! 51..84 '{ ...; }; }': () 61..62 'x': u32 70..81 '{ return; }': u32 72..78 'return': ! 96..125 '{ ... {}; }': () 106..107 'x': u32 115..122 'loop {}': ! 120..122 '{}': () 137..170 '{ ...} }; }': () 147..148 'x': u32 156..167 '{ loop {} }': u32 158..165 'loop {}': ! 163..165 '{}': () 182..246 '{ ...} }; }': () 192..193 'x': u32 201..243 '{ if t...}; } }': u32 203..241 'if tru... {}; }': u32 206..210 'true': bool 211..223 '{ loop {}; }': u32 213..220 'loop {}': ! 218..220 '{}': () 229..241 '{ loop {}; }': u32 231..238 'loop {}': ! 236..238 '{}': () 258..310 '{ ...; }; }': () 268..269 'x': u32 277..307 '{ let ...; }; }': u32 283..284 'y': u32 292..304 '{ loop {}; }': u32 294..301 'loop {}': ! 299..301 '{}': () "]], ); } #[test] fn diverging_expression_2() { check_infer_with_mismatches( r#" //- /main.rs fn test1() { // should give type mismatch let x: u32 = { loop {}; "foo" }; } "#, expect![[r#" 11..84 '{ ..." }; }': () 54..55 'x': u32 63..81 '{ loop...foo" }': u32 65..72 'loop {}': ! 70..72 '{}': () 74..79 '"foo"': &'static str 74..79: expected u32, got &'static str "#]], ); } #[test] fn diverging_expression_3_break() { check_infer_with_mismatches( r" //- minicore: iterator //- /main.rs fn test1() { // should give type mismatch let x: u32 = { loop { break; } }; } fn test2() { // should give type mismatch let x: u32 = { for a in b { break; }; }; // should give type mismatch as well let x: u32 = { for a in b {}; }; // should give type mismatch as well let x: u32 = { for a in b { return; }; }; } fn test3() { // should give type mismatch let x: u32 = { while true { break; }; }; // should give type mismatch as well -- there's an implicit break, even if it's never hit let x: u32 = { while true {}; }; // should give type mismatch as well let x: u32 = { while true { return; }; }; } ", expect![[r#" 11..85 '{ ...} }; }': () 54..55 'x': u32 63..82 '{ loop...k; } }': u32 65..80 'loop { break; }': () 70..80 '{ break; }': () 72..77 'break': ! 65..80: expected u32, got () 97..343 '{ ...; }; }': () 140..141 'x': u32 149..175 '{ for ...; }; }': u32 151..172 'for a ...eak; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 151..172 'for a ...eak; }': <{unknown} as IntoIterator>::IntoIter 151..172 'for a ...eak; }': ! 151..172 'for a ...eak; }': {unknown} 151..172 'for a ...eak; }': &'? mut {unknown} 151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 151..172 'for a ...eak; }': Option<<{unknown} as Iterator>::Item> 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 151..172 'for a ...eak; }': () 155..156 'a': {unknown} 160..161 'b': {unknown} 162..172 '{ break; }': () 164..169 'break': ! 226..227 'x': u32 235..253 '{ for ... {}; }': u32 237..250 'for a in b {}': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 237..250 'for a in b {}': <{unknown} as IntoIterator>::IntoIter 237..250 'for a in b {}': ! 237..250 'for a in b {}': {unknown} 237..250 'for a in b {}': &'? mut {unknown} 237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 237..250 'for a in b {}': Option<<{unknown} as Iterator>::Item> 237..250 'for a in b {}': () 237..250 'for a in b {}': () 237..250 'for a in b {}': () 237..250 'for a in b {}': () 241..242 'a': {unknown} 246..247 'b': {unknown} 248..250 '{}': () 304..305 'x': u32 313..340 '{ for ...; }; }': u32 315..337 'for a ...urn; }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter 315..337 'for a ...urn; }': <{unknown} as IntoIterator>::IntoIter 315..337 'for a ...urn; }': ! 315..337 'for a ...urn; }': {unknown} 315..337 'for a ...urn; }': &'? mut {unknown} 315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item> 315..337 'for a ...urn; }': Option<<{unknown} as Iterator>::Item> 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 315..337 'for a ...urn; }': () 319..320 'a': {unknown} 324..325 'b': {unknown} 326..337 '{ return; }': () 328..334 'return': ! 149..175: expected u32, got () 235..253: expected u32, got () 313..340: expected u32, got () 355..654 '{ ...; }; }': () 398..399 'x': u32 407..433 '{ whil...; }; }': u32 409..430 'while ...eak; }': ! 409..430 'while ...eak; }': () 409..430 'while ...eak; }': () 415..419 'true': bool 420..430 '{ break; }': () 422..427 'break': ! 537..538 'x': u32 546..564 '{ whil... {}; }': u32 548..561 'while true {}': ! 548..561 'while true {}': () 548..561 'while true {}': () 554..558 'true': bool 559..561 '{}': () 615..616 'x': u32 624..651 '{ whil...; }; }': u32 626..648 'while ...urn; }': ! 626..648 'while ...urn; }': () 626..648 'while ...urn; }': () 632..636 'true': bool 637..648 '{ return; }': () 639..645 'return': ! 407..433: expected u32, got () 546..564: expected u32, got () 624..651: expected u32, got () "#]], ); } #[test] fn let_else_must_diverge() { check_infer_with_mismatches( r#" fn f() { let 1 = 2 else { return; }; } "#, expect![[r#" 7..54 '{ ... }; }': () 17..18 '1': i32 17..18 '1': i32 21..22 '2': i32 28..51 '{ ... }': ! 38..44 'return': ! "#]], ); check_infer_with_mismatches( r#" fn f() { let 1 = 2 else {}; } "#, expect![[r#" 7..33 '{ ... {}; }': () 17..18 '1': i32 17..18 '1': i32 21..22 '2': i32 28..30 '{}': ! 28..30: expected !, got () "#]], ); } #[test] fn issue_11837() { check_no_mismatches( r#" //- minicore: result enum MyErr { Err1, Err2, } fn example_ng() { let value: Result = Ok(3); loop { let ret = match value { Ok(value) => value, Err(ref err) => { match err { MyErr::Err1 => break, MyErr::Err2 => continue, }; } }; } } "#, ); } #[test] fn issue_11814() { check_no_mismatches( r#" fn example() -> bool { match 1 { _ => return true, }; } "#, ); } #[test] fn reservation_impl_should_be_ignored() { // See rust-lang/rust#64631. check_types( r#" //- minicore: from struct S; #[rustc_reservation_impl] impl From for T {} fn foo>(_: U) -> T { loop {} } fn test() { let s = foo(S); //^ S } "#, ); } #[test] fn diverging_place_match1() { check_infer_with_mismatches( r#" //- minicore: sized fn not_a_read() -> ! { unsafe { let x: *const ! = 0 as _; let _: ! = *x; } } "#, expect![[r#" 21..100 '{ ... } }': ! 27..98 'unsafe... }': ! 48..49 'x': *const ! 62..63 '0': i32 62..68 '0 as _': *const ! 82..83 '_': ! 89..91 '*x': ! 90..91 'x': *const ! 27..98: expected !, got () "#]], ) } #[test] fn diverging_place_match2() { check_infer_with_mismatches( r#" //- minicore: sized fn not_a_read_implicit() -> ! { unsafe { let x: *const ! = 0 as _; let _ = *x; } } "#, expect![[r#" 30..106 '{ ... } }': ! 36..104 'unsafe... }': ! 57..58 'x': *const ! 71..72 '0': i32 71..77 '0 as _': *const ! 91..92 '_': ! 95..97 '*x': ! 96..97 'x': *const ! 36..104: expected !, got () "#]], ) } #[test] fn diverging_place_match3() { check_infer_with_mismatches( r#" //- minicore: sized fn not_a_read_guide_coercion() -> ! { unsafe { let x: *const ! = 0 as _; let _: () = *x; } } "#, expect![[r#" 36..116 '{ ... } }': ! 42..114 'unsafe... }': ! 63..64 'x': *const ! 77..78 '0': i32 77..83 '0 as _': *const ! 97..98 '_': () 105..107 '*x': ! 106..107 'x': *const ! 42..114: expected !, got () 105..107: expected (), got ! "#]], ) } #[test] fn diverging_place_match4() { check_infer_with_mismatches( r#" //- minicore: sized fn empty_match() -> ! { unsafe { let x: *const ! = 0 as _; match *x { _ => {} }; } } "#, expect![[r#" 22..108 '{ ... } }': ! 28..106 'unsafe... }': ! 49..50 'x': *const ! 63..64 '0': i32 63..69 '0 as _': *const ! 79..99 'match ...> {} }': () 85..87 '*x': ! 86..87 'x': *const ! 90..91 '_': ! 95..97 '{}': () 28..106: expected !, got () "#]], ) } #[test] fn diverging_place_match5() { check_infer_with_mismatches( r#" //- minicore: sized fn field_projection() -> ! { unsafe { let x: *const (!, ()) = 0 as _; let _ = (*x).0; } } "#, expect![[r#" 27..113 '{ ... } }': ! 33..111 'unsafe... }': ! 54..55 'x': *const (!, ()) 74..75 '0': i32 74..80 '0 as _': *const (!, ()) 94..95 '_': ! 98..104 '(*x).0': ! 99..101 '*x': (!, ()) 100..101 'x': *const (!, ()) 33..111: expected !, got () "#]], ) } #[test] fn diverging_place_match6() { check_infer_with_mismatches( r#" //- minicore: sized fn covered_arm() -> ! { unsafe { let x: *const ! = 0 as _; let (_ | 1i32) = *x; } } "#, expect![[r#" 22..107 '{ ... } }': ! 28..105 'unsafe... }': ! 49..50 'x': *const ! 63..64 '0': i32 63..69 '0 as _': *const ! 84..85 '_': ! 84..92 '_ | 1i32': ! 88..92 '1i32': i32 88..92 '1i32': i32 96..98 '*x': ! 97..98 'x': *const ! 28..105: expected !, got () 88..92: expected !, got i32 "#]], ) } #[test] fn diverging_place_match7() { check_infer_with_mismatches( r#" //- minicore: sized fn uncovered_arm() -> ! { unsafe { let x: *const ! = 0 as _; let (1i32 | _) = *x; } } "#, expect![[r#" 24..109 '{ ... } }': ! 30..107 'unsafe... }': ! 51..52 'x': *const ! 65..66 '0': i32 65..71 '0 as _': *const ! 86..90 '1i32': i32 86..90 '1i32': i32 86..94 '1i32 | _': ! 93..94 '_': ! 98..100 '*x': ! 99..100 'x': *const ! 30..107: expected !, got () 86..90: expected !, got i32 "#]], ) } #[test] fn diverging_place_match8() { check_infer_with_mismatches( r#" //- minicore: sized fn coerce_ref_binding() -> ! { unsafe { let x: *const ! = 0 as _; let ref _x: () = *x; } } "#, expect![[r#" 29..114 '{ ... } }': ! 35..112 'unsafe... }': ! 56..57 'x': *const ! 70..71 '0': i32 70..76 '0 as _': *const ! 90..96 'ref _x': &'? () 103..105 '*x': ! 104..105 'x': *const ! 103..105: expected (), got ! "#]], ) } #[test] fn diverging_place_match_ref_mut() { check_infer_with_mismatches( r#" //- minicore: sized fn coerce_ref_mut_binding() -> ! { unsafe { let x: *mut ! = 0 as _; let ref mut _x: () = *x; } } "#, expect![[r#" 33..120 '{ ... } }': ! 39..118 'unsafe... }': ! 60..61 'x': *mut ! 72..73 '0': i32 72..78 '0 as _': *mut ! 92..102 'ref mut _x': &'? mut () 109..111 '*x': ! 110..111 'x': *mut ! 109..111: expected (), got ! "#]], ) } #[test] fn assign_never_place_no_mismatch() { check_no_mismatches( r#" //- minicore: sized fn foo() { unsafe { let p: *mut ! = 0 as _; let mut x: () = (); x = *p; } } "#, ); } #[test] fn never_place_isnt_diverging() { check_infer_with_mismatches( r#" //- minicore: sized fn make_up_a_pointer() -> *const T { unsafe { let x: *const ! = 0 as _; &raw const *x } } "#, expect![[r#" 38..116 '{ ... } }': *const T 44..114 'unsafe... }': *const T 65..66 'x': *const ! 79..80 '0': i32 79..85 '0 as _': *const ! 95..108 '&raw const *x': *const ! 106..108 '*x': ! 107..108 'x': *const ! 95..108: expected *const T, got *const ! "#]], ) } #[test] fn diverging_destructuring_assignment() { check_infer_with_mismatches( r#" fn foo() { let n = match 42 { 0 => _ = loop {}, _ => 0, }; } "#, expect![[r#" 9..84 '{ ... }; }': () 19..20 'n': i32 23..81 'match ... }': i32 29..31 '42': i32 42..43 '0': i32 42..43 '0': i32 47..48 '_': ! 47..58 '_ = loop {}': i32 51..58 'loop {}': ! 56..58 '{}': () 68..69 '_': i32 73..74 '0': i32 "#]], ); }