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/infer.rs | 82 ++++++++++++++------- crates/ra_hir/src/ty/tests.rs | 127 ++++++++++++++++----------------- crates/ra_hir/src/ty/tests/coercion.rs | 103 ++++++++++++++++++++++++-- 3 files changed, 216 insertions(+), 96 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index ba63050a9..db3377357 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -14,7 +14,7 @@ //! the `ena` crate, which is extracted from rustc. use std::borrow::Cow; -use std::iter::repeat; +use std::iter::{repeat, repeat_with}; use std::mem; use std::ops::Index; use std::sync::Arc; @@ -876,10 +876,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } /// Infer type of expression with possibly implicit coerce to the expected type. + /// Return the type after possible coercion. fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { let ty = self.infer_expr_inner(expr, &expected); - self.coerce(&ty, &expected.ty); - ty + let ty = if !self.coerce(&ty, &expected.ty) { + self.result + .type_mismatches + .insert(expr, TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }); + // Return actual type when type mismatch. + // This is needed for diagnostic when return type mismatch. + ty + } else if expected.ty == Ty::Unknown { + ty + } else { + expected.ty.clone() + }; + + self.resolve_ty_as_possible(&mut vec![], ty) } /// Merge two types from different branches, with possible implicit coerce. @@ -1328,6 +1341,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.write_variant_resolution(tgt_expr.into(), variant); } + self.unify(&ty, &expected.ty); + let substs = ty.substs().unwrap_or_else(Substs::empty); for (field_idx, field) in fields.iter().enumerate() { let field_ty = def_id @@ -1343,7 +1358,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }) .map_or(Ty::Unknown, |field| field.ty(self.db)) .subst(&substs); - self.infer_expr(field.expr, &Expectation::has_type(field_ty)); + self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); } if let Some(expr) = spread { self.infer_expr(*expr, &Expectation::has_type(ty.clone())); @@ -1513,35 +1528,41 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Ty::Unknown } Expr::Tuple { exprs } => { - let mut ty_vec = Vec::with_capacity(exprs.len()); - for arg in exprs.iter() { - ty_vec.push(self.infer_expr(*arg, &Expectation::none())); + let mut tys = match &expected.ty { + ty_app!(TypeCtor::Tuple { .. }, st) => st + .iter() + .cloned() + .chain(repeat_with(|| self.new_type_var())) + .take(exprs.len()) + .collect::>(), + _ => (0..exprs.len()).map(|_| self.new_type_var()).collect(), + }; + + for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { + self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); } - Ty::apply( - TypeCtor::Tuple { cardinality: ty_vec.len() as u16 }, - Substs(ty_vec.into()), - ) + Ty::apply(TypeCtor::Tuple { cardinality: tys.len() as u16 }, Substs(tys.into())) } Expr::Array(array) => { let elem_ty = match &expected.ty { - Ty::Apply(a_ty) => match a_ty.ctor { - TypeCtor::Slice | TypeCtor::Array => { - Ty::clone(&a_ty.parameters.as_single()) - } - _ => self.new_type_var(), - }, + ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { + st.as_single().clone() + } _ => self.new_type_var(), }; match array { Array::ElementList(items) => { for expr in items.iter() { - self.infer_expr(*expr, &Expectation::has_type(elem_ty.clone())); + self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone())); } } Array::Repeat { initializer, repeat } => { - self.infer_expr(*initializer, &Expectation::has_type(elem_ty.clone())); + self.infer_expr_coerce( + *initializer, + &Expectation::has_type(elem_ty.clone()), + ); self.infer_expr( *repeat, &Expectation::has_type(Ty::simple(TypeCtor::Int( @@ -1588,12 +1609,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Statement::Let { pat, type_ref, initializer } => { let decl_ty = type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown); - let decl_ty = self.insert_type_vars(decl_ty); + + // Always use the declared type when specified + let mut ty = decl_ty.clone(); + if let Some(expr) = initializer { - self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone())); + let actual_ty = + self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone())); + if decl_ty == Ty::Unknown { + ty = actual_ty; + } } - let ty = self.resolve_ty_as_possible(&mut vec![], decl_ty); + let ty = self.resolve_ty_as_possible(&mut vec![], ty); self.infer_pat(*pat, &ty, BindingMode::default()); } Statement::Expr(expr) => { @@ -1601,9 +1629,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } } - let ty = - if let Some(expr) = tail { self.infer_expr_inner(expr, expected) } else { Ty::unit() }; - ty + + if let Some(expr) = tail { + self.infer_expr_coerce(expr, expected) + } else { + self.coerce(&Ty::unit(), &expected.ty); + Ty::unit() + } } fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) { diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index cd5a05092..4362bb27a 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -239,17 +239,23 @@ fn test() { let a = 1isize; let b: usize = 1; let c = b; + let d: u32; + let e; + let f: i32 = e; } "#), @r###" - - [11; 71) '{ ...= b; }': () + [11; 118) '{ ...= e; }': () [21; 22) 'a': isize [25; 31) '1isize': isize [41; 42) 'b': usize [52; 53) '1': usize [63; 64) 'c': usize [67; 68) 'b': usize + [78; 79) 'd': u32 + [94; 95) 'e': i32 + [105; 106) 'f': i32 + [114; 115) 'e': i32 "### ); } @@ -331,14 +337,14 @@ fn test() { "#), @r###" [45; 49) 'self': &[T] - [56; 79) '{ ... }': ! + [56; 79) '{ ... }': T [66; 73) 'loop {}': ! [71; 73) '{}': () [133; 160) '{ ...o"); }': () [139; 149) '<[_]>::foo': fn foo(&[T]) -> T [139; 157) '<[_]>:..."foo")': u8 [150; 156) 'b"foo"': &[u8] -"### + "### ); } @@ -817,7 +823,7 @@ struct A(T); impl A { fn foo(&self) -> &T { - self.0 + &self.0 } } @@ -837,28 +843,29 @@ fn test() { @r###" [68; 72) 'self': &Self [139; 143) 'self': &A - [151; 173) '{ ... }': T - [161; 165) 'self': &A - [161; 167) 'self.0': T - [254; 258) 'self': &B - [277; 300) '{ ... }': &T - [287; 294) '&self.0': &T - [288; 292) 'self': &B - [288; 294) 'self.0': T - [314; 352) '{ ...))); }': () - [324; 325) 't': &i32 - [328; 334) 'A::foo': fn foo(&A) -> &T - [328; 349) 'A::foo...42))))': &i32 - [335; 348) '&&B(B(A(42)))': &&B>> - [336; 348) '&B(B(A(42)))': &B>> - [337; 338) 'B': B>>(T) -> B - [337; 348) 'B(B(A(42)))': B>> - [339; 340) 'B': B>(T) -> B - [339; 347) 'B(A(42))': B> - [341; 342) 'A': A(T) -> A - [341; 346) 'A(42)': A - [343; 345) '42': i32 -"### + [151; 174) '{ ... }': &T + [161; 168) '&self.0': &T + [162; 166) 'self': &A + [162; 168) 'self.0': T + [255; 259) 'self': &B + [278; 301) '{ ... }': &T + [288; 295) '&self.0': &T + [289; 293) 'self': &B + [289; 295) 'self.0': T + [315; 353) '{ ...))); }': () + [325; 326) 't': &i32 + [329; 335) 'A::foo': fn foo(&A) -> &T + [329; 350) 'A::foo...42))))': &i32 + [336; 349) '&&B(B(A(42)))': &&B>> + [337; 349) '&B(B(A(42)))': &B>> + [338; 339) 'B': B>>(T) -> B + [338; 349) 'B(B(A(42)))': B>> + [340; 341) 'B': B>(T) -> B + [340; 348) 'B(A(42))': B> + [342; 343) 'A': A(T) -> A + [342; 347) 'A(42)': A + [344; 346) '42': i32 + "### ); } @@ -1109,13 +1116,12 @@ fn test(x: &str, y: isize) { let b = [a, ["b"]]; let x: [u8; 0] = []; - let z: &[u8] = &[1, 2, 3]; } "#), @r###" [9; 10) 'x': &str [18; 19) 'y': isize - [28; 324) '{ ... 3]; }': () + [28; 293) '{ ... []; }': () [38; 39) 'a': [&str;_] [42; 45) '[x]': [&str;_] [43; 44) 'x': &str @@ -1165,12 +1171,6 @@ fn test(x: &str, y: isize) { [260; 263) '"b"': &str [275; 276) 'x': [u8;_] [288; 290) '[]': [u8;_] - [300; 301) 'z': &[u8] - [311; 321) '&[1, 2, 3]': &[u8;_] - [312; 321) '[1, 2, 3]': [u8;_] - [313; 314) '1': u8 - [316; 317) '2': u8 - [319; 320) '3': u8 "### ); } @@ -1892,8 +1892,7 @@ fn test() { } "#), @r###" - - [80; 104) '{ ... }': ! + [80; 104) '{ ... }': Gen [90; 98) 'loop { }': ! [95; 98) '{ }': () [118; 146) '{ ...e(); }': () @@ -1923,8 +1922,7 @@ fn test() { } "#), @r###" - - [76; 100) '{ ... }': ! + [76; 100) '{ ... }': Gen [86; 94) 'loop { }': ! [91; 94) '{ }': () [114; 149) '{ ...e(); }': () @@ -1955,8 +1953,7 @@ fn test() { } "#), @r###" - - [102; 126) '{ ... }': ! + [102; 126) '{ ... }': Gen [112; 120) 'loop { }': ! [117; 120) '{ }': () [140; 180) '{ ...e(); }': () @@ -2100,7 +2097,7 @@ fn test() { @r###" [11; 48) '{ ...&y]; }': () [21; 22) 'y': &{unknown} - [25; 32) 'unknown': &&{unknown} + [25; 32) 'unknown': &{unknown} [38; 45) '[y, &y]': [&&{unknown};_] [39; 40) 'y': &{unknown} [42; 44) '&y': &&{unknown} @@ -2124,11 +2121,11 @@ fn test() { @r###" [11; 80) '{ ...x)]; }': () [21; 22) 'x': &&{unknown} - [25; 32) 'unknown': &&&{unknown} + [25; 32) 'unknown': &&{unknown} [42; 43) 'y': &&{unknown} - [46; 53) 'unknown': &&&{unknown} - [59; 77) '[(x, y..., &x)]': [(&&{unknown}, &&{unknown});_] - [60; 66) '(x, y)': (&&{unknown}, &&{unknown}) + [46; 53) 'unknown': &&{unknown} + [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_] + [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown}) [61; 62) 'x': &&{unknown} [64; 65) 'y': &&{unknown} [68; 76) '(&y, &x)': (&&&{unknown}, &&&{unknown}) @@ -2149,7 +2146,7 @@ fn id(x: T) -> T { } fn clone(x: &T) -> T { - x + *x } fn test() { @@ -2160,26 +2157,26 @@ fn test() { } "#), @r###" - [10; 11) 'x': T [21; 30) '{ x }': T [27; 28) 'x': T [44; 45) 'x': &T - [56; 65) '{ x }': &T - [62; 63) 'x': &T - [77; 157) '{ ...(1); }': () - [87; 88) 'y': u32 - [91; 96) '10u32': u32 - [102; 104) 'id': fn id(T) -> T - [102; 107) 'id(y)': u32 - [105; 106) 'y': u32 - [117; 118) 'x': bool - [127; 132) 'clone': fn clone(&T) -> T - [127; 135) 'clone(z)': bool - [133; 134) 'z': &bool - [141; 151) 'id::': fn id(T) -> T - [141; 154) 'id::(1)': i128 - [152; 153) '1': i128 + [56; 66) '{ *x }': T + [62; 64) '*x': T + [63; 64) 'x': &T + [78; 158) '{ ...(1); }': () + [88; 89) 'y': u32 + [92; 97) '10u32': u32 + [103; 105) 'id': fn id(T) -> T + [103; 108) 'id(y)': u32 + [106; 107) 'y': u32 + [118; 119) 'x': bool + [128; 133) 'clone': fn clone(&T) -> T + [128; 136) 'clone(z)': bool + [134; 135) 'z': &bool + [142; 152) 'id::': fn id(T) -> T + [142; 155) 'id::(1)': i128 + [153; 154) '1': i128 "### ); } @@ -3404,7 +3401,7 @@ impl S { } fn test(s: Arc) { - (*s, s.foo())<|> + (*s, s.foo())<|>; } "#, ); @@ -3488,7 +3485,7 @@ impl S { } fn test(s: Arc) { - (*s, s.foo())<|> + (*s, s.foo())<|>; } "#, ); 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