From bf161fa3e58d57d9b15bd965405036d834f18595 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Wed, 18 Sep 2019 03:59:51 +0800 Subject: Better handle never type and branch merging Split out tests for never type to another file --- crates/ra_hir/src/ty/tests/never_type.rs | 258 +++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 crates/ra_hir/src/ty/tests/never_type.rs (limited to 'crates/ra_hir/src/ty/tests') diff --git a/crates/ra_hir/src/ty/tests/never_type.rs b/crates/ra_hir/src/ty/tests/never_type.rs new file mode 100644 index 000000000..b9af918e9 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/never_type.rs @@ -0,0 +1,258 @@ +use super::type_at; + +#[test] +fn infer_never1() { + let t = type_at( + r#" +//- /main.rs +fn test() { + let t = return; + t<|>; +} +"#, + ); + assert_eq!(t, "!"); +} + +#[test] +fn infer_never2() { + let t = type_at( + r#" +//- /main.rs +trait Foo { fn gen() -> Self; } +impl Foo for ! { fn gen() -> Self { loop {} } } +impl Foo for () { fn gen() -> Self { loop {} } } + +fn test() { + let a = Foo::gen(); + if false { a } else { loop {} }; + a<|>; +} +"#, + ); + assert_eq!(t, "!"); +} + +#[test] +fn infer_never3() { + let t = type_at( + r#" +//- /main.rs +trait Foo { fn gen() -> Self; } +impl Foo for ! { fn gen() -> Self { loop {} } } +impl Foo for () { fn gen() -> Self { loop {} } } + +fn test() { + let a = Foo::gen(); + if false { loop {} } else { a }; + a<|>; +} +"#, + ); + assert_eq!(t, "!"); +} + +#[test] +fn never_type_in_generic_args() { + let t = type_at( + r#" +//- /main.rs +enum Option { None, Some(T) } + +fn test() { + let a = if true { Option::None } else { Option::Some(return) }; + a<|>; +} +"#, + ); + assert_eq!(t, "Option"); +} + +#[test] +fn never_type_can_be_reinferred1() { + let t = type_at( + r#" +//- /main.rs +trait Foo { fn gen() -> Self; } +impl Foo for ! { fn gen() -> Self { loop {} } } +impl Foo for () { fn gen() -> Self { loop {} } } + +fn test() { + let a = Foo::gen(); + if false { loop {} } else { a }; + a<|>; + if false { a }; +} +"#, + ); + assert_eq!(t, "()"); +} + +#[test] +fn never_type_can_be_reinferred2() { + let t = type_at( + r#" +//- /main.rs +enum Option { None, Some(T) } + +fn test() { + let a = if true { Option::None } else { Option::Some(return) }; + a<|>; + match 42 { + 42 => a, + _ => Option::Some(42), + }; +} +"#, + ); + assert_eq!(t, "Option"); +} +#[test] +fn never_type_can_be_reinferred3() { + let t = type_at( + r#" +//- /main.rs +enum Option { None, Some(T) } + +fn test() { + let a = if true { Option::None } else { Option::Some(return) }; + a<|>; + match 42 { + 42 => a, + _ => Option::Some("str"), + }; +} +"#, + ); + assert_eq!(t, "Option<&str>"); +} + +#[test] +fn match_no_arm() { + let t = type_at( + r#" +//- /main.rs +enum Void {} + +fn test(a: Void) { + let t = match a {}; + t<|>; +} +"#, + ); + assert_eq!(t, "!"); +} + +#[test] +fn if_never() { + let t = type_at( + r#" +//- /main.rs +fn test() { + let i = if true { + loop {} + } else { + 3.0 + }; + i<|> + () +} +"#, + ); + assert_eq!(t, "f64"); +} + +#[test] +fn if_else_never() { + let t = type_at( + r#" +//- /main.rs +fn test(input: bool) { + let i = if input { + 2.0 + } else { + return + }; + i<|> + () +} +"#, + ); + assert_eq!(t, "f64"); +} + +#[test] +fn match_first_arm_never() { + let t = type_at( + r#" +//- /main.rs +fn test(a: i32) { + let i = match a { + 1 => return, + 2 => 2.0, + 3 => loop {}, + _ => 3.0, + }; + i<|> + () +} +"#, + ); + assert_eq!(t, "f64"); +} + +#[test] +fn match_second_arm_never() { + let t = type_at( + r#" +//- /main.rs +fn test(a: i32) { + let i = match a { + 1 => 3.0, + 2 => loop {}, + 3 => 3.0, + _ => return, + }; + i<|> + () +} +"#, + ); + assert_eq!(t, "f64"); +} + +#[test] +fn match_all_arms_never() { + let t = type_at( + r#" +//- /main.rs +fn test(a: i32) { + let i = match a { + 2 => return, + _ => loop {}, + }; + i<|> + () +} +"#, + ); + assert_eq!(t, "!"); +} + +#[test] +fn match_no_never_arms() { + let t = type_at( + r#" +//- /main.rs +fn test(a: i32) { + let i = match a { + 2 => 2.0, + _ => 3.0, + }; + i<|> + () +} +"#, + ); + assert_eq!(t, "f64"); +} -- cgit v1.2.3 From 5807e261c27e4964fc6a8d2b8cf02e548292b940 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Thu, 19 Sep 2019 00:36:12 +0800 Subject: Support custom `CoerceUnsized` Split out tests about coercion --- crates/ra_hir/src/ty/tests/coercion.rs | 278 +++++++++++++++++++++++++++++++ crates/ra_hir/src/ty/tests/never_type.rs | 36 ++-- 2 files changed, 290 insertions(+), 24 deletions(-) create mode 100644 crates/ra_hir/src/ty/tests/coercion.rs (limited to 'crates/ra_hir/src/ty/tests') diff --git a/crates/ra_hir/src/ty/tests/coercion.rs b/crates/ra_hir/src/ty/tests/coercion.rs new file mode 100644 index 000000000..d80d3fb6f --- /dev/null +++ b/crates/ra_hir/src/ty/tests/coercion.rs @@ -0,0 +1,278 @@ +use insta::assert_snapshot; +use test_utils::covers; + +// Infer with some common definitions and impls. +fn infer(source: &str) -> String { + let defs = r#" + #[lang = "sized"] + pub trait Sized {} + #[lang = "unsize"] + pub trait Unsize {} + #[lang = "coerce_unsized"] + pub trait CoerceUnsized {} + + impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} + impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + "#; + + // Append to the end to keep positions unchanged. + super::infer(&format!("{}{}", source, defs)) +} + +#[test] +fn infer_let_stmt_coerce() { + assert_snapshot!( + infer(r#" +fn test() { + let x: &[i32] = &[1]; +} +"#), + @r###" + [11; 40) '{ ...[1]; }': () + [21; 22) 'x': &[i32] + [33; 37) '&[1]': &[i32;_] + [34; 37) '[1]': [i32;_] + [35; 36) '1': i32 + "###); +} + +#[test] +fn infer_custom_coerce_unsized() { + assert_snapshot!( + infer(r#" +struct A(*const T); +struct B(*const T); +struct C { inner: *const T } + +impl, U: ?Sized> CoerceUnsized> for B {} +impl, U: ?Sized> CoerceUnsized> for C {} + +fn foo1(x: A<[T]>) -> A<[T]> { x } +fn foo2(x: B<[T]>) -> B<[T]> { x } +fn foo3(x: C<[T]>) -> C<[T]> { x } + +fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { + let d = foo1(a); + let e = foo2(b); + let f = foo3(c); +} +"#), + @r###" + [258; 259) 'x': A<[T]> + [279; 284) '{ x }': A<[T]> + [281; 282) 'x': A<[T]> + [296; 297) 'x': B<[T]> + [317; 322) '{ x }': B<[T]> + [319; 320) 'x': B<[T]> + [334; 335) 'x': C<[T]> + [355; 360) '{ x }': C<[T]> + [357; 358) 'x': C<[T]> + [370; 371) 'a': A<[u8;_]> + [385; 386) 'b': B<[u8;_]> + [400; 401) 'c': C<[u8;_]> + [415; 481) '{ ...(c); }': () + [425; 426) 'd': A<[{unknown}]> + [429; 433) 'foo1': fn foo1<{unknown}>(A<[T]>) -> A<[T]> + [429; 436) 'foo1(a)': A<[{unknown}]> + [434; 435) 'a': A<[u8;_]> + [446; 447) 'e': B<[u8]> + [450; 454) 'foo2': fn foo2(B<[T]>) -> B<[T]> + [450; 457) 'foo2(b)': B<[u8]> + [455; 456) 'b': B<[u8;_]> + [467; 468) 'f': C<[u8]> + [471; 475) 'foo3': fn foo3(C<[T]>) -> C<[T]> + [471; 478) 'foo3(c)': C<[u8]> + [476; 477) 'c': C<[u8;_]> + "### + ); +} + +#[test] +fn infer_if_coerce() { + assert_snapshot!( + infer(r#" +fn foo(x: &[T]) -> &[T] { loop {} } +fn test() { + let x = if true { + foo(&[1]) + } else { + &[1] + }; +} +"#), + @r###" + [11; 12) 'x': &[T] + [28; 39) '{ loop {} }': ! + [30; 37) 'loop {}': ! + [35; 37) '{}': () + [50; 126) '{ ... }; }': () + [60; 61) 'x': &[i32] + [64; 123) 'if tru... }': &[i32] + [67; 71) 'true': bool + [72; 97) '{ ... }': &[i32] + [82; 85) 'foo': fn foo(&[T]) -> &[T] + [82; 91) 'foo(&[1])': &[i32] + [86; 90) '&[1]': &[i32;_] + [87; 90) '[1]': [i32;_] + [88; 89) '1': i32 + [103; 123) '{ ... }': &[i32;_] + [113; 117) '&[1]': &[i32;_] + [114; 117) '[1]': [i32;_] + [115; 116) '1': i32 +"### + ); +} + +#[test] +fn infer_if_else_coerce() { + assert_snapshot!( + infer(r#" +fn foo(x: &[T]) -> &[T] { loop {} } +fn test() { + let x = if true { + &[1] + } else { + foo(&[1]) + }; +} +"#), + @r###" + [11; 12) 'x': &[T] + [28; 39) '{ loop {} }': ! + [30; 37) 'loop {}': ! + [35; 37) '{}': () + [50; 126) '{ ... }; }': () + [60; 61) 'x': &[i32] + [64; 123) 'if tru... }': &[i32] + [67; 71) 'true': bool + [72; 92) '{ ... }': &[i32;_] + [82; 86) '&[1]': &[i32;_] + [83; 86) '[1]': [i32;_] + [84; 85) '1': i32 + [98; 123) '{ ... }': &[i32] + [108; 111) 'foo': fn foo(&[T]) -> &[T] + [108; 117) 'foo(&[1])': &[i32] + [112; 116) '&[1]': &[i32;_] + [113; 116) '[1]': [i32;_] + [114; 115) '1': i32 +"### + ); +} + +#[test] +fn infer_match_first_coerce() { + assert_snapshot!( + infer(r#" +fn foo(x: &[T]) -> &[T] { loop {} } +fn test(i: i32) { + let x = match i { + 2 => foo(&[2]), + 1 => &[1], + _ => &[3], + }; +} +"#), + @r###" + [11; 12) 'x': &[T] + [28; 39) '{ loop {} }': ! + [30; 37) 'loop {}': ! + [35; 37) '{}': () + [48; 49) 'i': i32 + [56; 150) '{ ... }; }': () + [66; 67) 'x': &[i32] + [70; 147) 'match ... }': &[i32] + [76; 77) 'i': i32 + [88; 89) '2': i32 + [93; 96) 'foo': fn foo(&[T]) -> &[T] + [93; 102) 'foo(&[2])': &[i32] + [97; 101) '&[2]': &[i32;_] + [98; 101) '[2]': [i32;_] + [99; 100) '2': i32 + [112; 113) '1': i32 + [117; 121) '&[1]': &[i32;_] + [118; 121) '[1]': [i32;_] + [119; 120) '1': i32 + [131; 132) '_': i32 + [136; 140) '&[3]': &[i32;_] + [137; 140) '[3]': [i32;_] + [138; 139) '3': i32 + "### + ); +} + +#[test] +fn infer_match_second_coerce() { + assert_snapshot!( + infer(r#" +fn foo(x: &[T]) -> &[T] { loop {} } +fn test(i: i32) { + let x = match i { + 1 => &[1], + 2 => foo(&[2]), + _ => &[3], + }; +} +"#), + @r###" + [11; 12) 'x': &[T] + [28; 39) '{ loop {} }': ! + [30; 37) 'loop {}': ! + [35; 37) '{}': () + [48; 49) 'i': i32 + [56; 150) '{ ... }; }': () + [66; 67) 'x': &[i32] + [70; 147) 'match ... }': &[i32] + [76; 77) 'i': i32 + [88; 89) '1': i32 + [93; 97) '&[1]': &[i32;_] + [94; 97) '[1]': [i32;_] + [95; 96) '1': i32 + [107; 108) '2': i32 + [112; 115) 'foo': fn foo(&[T]) -> &[T] + [112; 121) 'foo(&[2])': &[i32] + [116; 120) '&[2]': &[i32;_] + [117; 120) '[2]': [i32;_] + [118; 119) '2': i32 + [131; 132) '_': i32 + [136; 140) '&[3]': &[i32;_] + [137; 140) '[3]': [i32;_] + [138; 139) '3': i32 + "### + ); +} + +#[test] +fn coerce_merge_one_by_one1() { + covers!(coerce_merge_fail_fallback); + + assert_snapshot!( + infer(r#" +fn test() { + let t = &mut 1; + let x = match 1 { + 1 => t as *mut i32, + 2 => t as &i32, + _ => t as *const i32, + }; +} +"#), + @r###" + [11; 145) '{ ... }; }': () + [21; 22) 't': &mut i32 + [25; 31) '&mut 1': &mut i32 + [30; 31) '1': i32 + [41; 42) 'x': *const i32 + [45; 142) 'match ... }': *const i32 + [51; 52) '1': i32 + [63; 64) '1': i32 + [68; 69) 't': &mut i32 + [68; 81) 't as *mut i32': *mut i32 + [91; 92) '2': i32 + [96; 97) 't': &mut i32 + [96; 105) 't as &i32': &i32 + [115; 116) '_': i32 + [120; 121) 't': &mut i32 + [120; 135) 't as *const i32': *const i32 + "### + ); +} diff --git a/crates/ra_hir/src/ty/tests/never_type.rs b/crates/ra_hir/src/ty/tests/never_type.rs index b9af918e9..c202f545a 100644 --- a/crates/ra_hir/src/ty/tests/never_type.rs +++ b/crates/ra_hir/src/ty/tests/never_type.rs @@ -19,12 +19,10 @@ fn infer_never2() { let t = type_at( r#" //- /main.rs -trait Foo { fn gen() -> Self; } -impl Foo for ! { fn gen() -> Self { loop {} } } -impl Foo for () { fn gen() -> Self { loop {} } } +fn gen() -> T { loop {} } fn test() { - let a = Foo::gen(); + let a = gen(); if false { a } else { loop {} }; a<|>; } @@ -38,12 +36,10 @@ fn infer_never3() { let t = type_at( r#" //- /main.rs -trait Foo { fn gen() -> Self; } -impl Foo for ! { fn gen() -> Self { loop {} } } -impl Foo for () { fn gen() -> Self { loop {} } } +fn gen() -> T { loop {} } fn test() { - let a = Foo::gen(); + let a = gen(); if false { loop {} } else { a }; a<|>; } @@ -73,12 +69,10 @@ fn never_type_can_be_reinferred1() { let t = type_at( r#" //- /main.rs -trait Foo { fn gen() -> Self; } -impl Foo for ! { fn gen() -> Self { loop {} } } -impl Foo for () { fn gen() -> Self { loop {} } } +fn gen() -> T { loop {} } fn test() { - let a = Foo::gen(); + let a = gen(); if false { loop {} } else { a }; a<|>; if false { a }; @@ -154,8 +148,7 @@ fn test() { } else { 3.0 }; - i<|> - () + i<|>; } "#, ); @@ -173,8 +166,7 @@ fn test(input: bool) { } else { return }; - i<|> - () + i<|>; } "#, ); @@ -193,8 +185,7 @@ fn test(a: i32) { 3 => loop {}, _ => 3.0, }; - i<|> - () + i<|>; } "#, ); @@ -213,8 +204,7 @@ fn test(a: i32) { 3 => 3.0, _ => return, }; - i<|> - () + i<|>; } "#, ); @@ -231,8 +221,7 @@ fn test(a: i32) { 2 => return, _ => loop {}, }; - i<|> - () + i<|>; } "#, ); @@ -249,8 +238,7 @@ fn test(a: i32) { 2 => 2.0, _ => 3.0, }; - i<|> - () + i<|>; } "#, ); -- cgit v1.2.3 From 29e56b8ee480828b81011cfa16c055fa0c9c89fe Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Thu, 26 Sep 2019 05:56:55 +0800 Subject: Support all coercion places --- crates/ra_hir/src/ty/tests/coercion.rs | 103 +++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir/src/ty/tests') diff --git a/crates/ra_hir/src/ty/tests/coercion.rs b/crates/ra_hir/src/ty/tests/coercion.rs index d80d3fb6f..1530fcc63 100644 --- a/crates/ra_hir/src/ty/tests/coercion.rs +++ b/crates/ra_hir/src/ty/tests/coercion.rs @@ -19,6 +19,97 @@ fn infer(source: &str) -> String { super::infer(&format!("{}{}", source, defs)) } +#[test] +fn infer_block_expr_type_mismatch() { + assert_snapshot!( + infer(r#" +fn test() { + let a: i32 = { 1i64 }; +} +"#), + @r###" + [11; 41) '{ ...4 }; }': () + [21; 22) 'a': i32 + [30; 38) '{ 1i64 }': i64 + [32; 36) '1i64': i64 + "###); +} + +#[test] +fn coerce_places() { + assert_snapshot!( + infer(r#" +struct S { a: T } + +fn f(_: &[T]) -> T { loop {} } +fn g(_: S<&[T]>) -> T { loop {} } + +fn gen() -> *mut [T; 2] { loop {} } +fn test1() -> *mut [U] { + gen() +} + +fn test2() { + let arr: &[u8; 1] = &[1]; + + let a: &[_] = arr; + let b = f(arr); + let c: &[_] = { arr }; + let d = g(S { a: arr }); + let e: [&[_]; 1] = [arr]; + let f: [&[_]; 2] = [arr; 2]; + let g: (&[_], &[_]) = (arr, arr); +} +"#), + @r###" + [31; 32) '_': &[T] + [45; 56) '{ loop {} }': T + [47; 54) 'loop {}': ! + [52; 54) '{}': () + [65; 66) '_': S<&[T]> + [82; 93) '{ loop {} }': T + [84; 91) 'loop {}': ! + [89; 91) '{}': () + [122; 133) '{ loop {} }': *mut [T;_] + [124; 131) 'loop {}': ! + [129; 131) '{}': () + [160; 173) '{ gen() }': *mut [U] + [166; 169) 'gen': fn gen() -> *mut [T;_] + [166; 171) 'gen()': *mut [U;_] + [186; 420) '{ ...rr); }': () + [196; 199) 'arr': &[u8;_] + [212; 216) '&[1]': &[u8;_] + [213; 216) '[1]': [u8;_] + [214; 215) '1': u8 + [227; 228) 'a': &[u8] + [237; 240) 'arr': &[u8;_] + [250; 251) 'b': u8 + [254; 255) 'f': fn f(&[T]) -> T + [254; 260) 'f(arr)': u8 + [256; 259) 'arr': &[u8;_] + [270; 271) 'c': &[u8] + [280; 287) '{ arr }': &[u8] + [282; 285) 'arr': &[u8;_] + [297; 298) 'd': u8 + [301; 302) 'g': fn g(S<&[T]>) -> T + [301; 316) 'g(S { a: arr })': u8 + [303; 315) 'S { a: arr }': S<&[u8]> + [310; 313) 'arr': &[u8;_] + [326; 327) 'e': [&[u8];_] + [341; 346) '[arr]': [&[u8];_] + [342; 345) 'arr': &[u8;_] + [356; 357) 'f': [&[u8];_] + [371; 379) '[arr; 2]': [&[u8];_] + [372; 375) 'arr': &[u8;_] + [377; 378) '2': usize + [389; 390) 'g': (&[u8], &[u8]) + [407; 417) '(arr, arr)': (&[u8], &[u8]) + [408; 411) 'arr': &[u8;_] + [413; 416) 'arr': &[u8;_] + "### + ); +} + #[test] fn infer_let_stmt_coerce() { assert_snapshot!( @@ -102,7 +193,7 @@ fn test() { "#), @r###" [11; 12) 'x': &[T] - [28; 39) '{ loop {} }': ! + [28; 39) '{ loop {} }': &[T] [30; 37) 'loop {}': ! [35; 37) '{}': () [50; 126) '{ ... }; }': () @@ -119,7 +210,7 @@ fn test() { [113; 117) '&[1]': &[i32;_] [114; 117) '[1]': [i32;_] [115; 116) '1': i32 -"### + "### ); } @@ -138,7 +229,7 @@ fn test() { "#), @r###" [11; 12) 'x': &[T] - [28; 39) '{ loop {} }': ! + [28; 39) '{ loop {} }': &[T] [30; 37) 'loop {}': ! [35; 37) '{}': () [50; 126) '{ ... }; }': () @@ -155,7 +246,7 @@ fn test() { [112; 116) '&[1]': &[i32;_] [113; 116) '[1]': [i32;_] [114; 115) '1': i32 -"### + "### ); } @@ -174,7 +265,7 @@ fn test(i: i32) { "#), @r###" [11; 12) 'x': &[T] - [28; 39) '{ loop {} }': ! + [28; 39) '{ loop {} }': &[T] [30; 37) 'loop {}': ! [35; 37) '{}': () [48; 49) 'i': i32 @@ -215,7 +306,7 @@ fn test(i: i32) { "#), @r###" [11; 12) 'x': &[T] - [28; 39) '{ loop {} }': ! + [28; 39) '{ loop {} }': &[T] [30; 37) 'loop {}': ! [35; 37) '{}': () [48; 49) 'i': i32 -- cgit v1.2.3