Support all coercion places

This commit is contained in:
uHOOCCOOHu 2019-09-26 05:56:55 +08:00
parent 5807e261c2
commit 29e56b8ee4
No known key found for this signature in database
GPG key ID: CED392DE0C483D00
3 changed files with 216 additions and 96 deletions

View file

@ -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::<Vec<_>>(),
_ => (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]) {

View file

@ -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<u8>(&[T]) -> T
[139; 157) '<[_]>:..."foo")': u8
[150; 156) 'b"foo"': &[u8]
"###
"###
);
}
@ -817,7 +823,7 @@ struct A<T>(T);
impl<T> A<T> {
fn foo(&self) -> &T {
self.0
&self.0
}
}
@ -837,28 +843,29 @@ fn test() {
@r###"
[68; 72) 'self': &Self
[139; 143) 'self': &A<T>
[151; 173) '{ ... }': T
[161; 165) 'self': &A<T>
[161; 167) 'self.0': T
[254; 258) 'self': &B<T>
[277; 300) '{ ... }': &T
[287; 294) '&self.0': &T
[288; 292) 'self': &B<T>
[288; 294) 'self.0': T
[314; 352) '{ ...))); }': ()
[324; 325) 't': &i32
[328; 334) 'A::foo': fn foo<i32>(&A<T>) -> &T
[328; 349) 'A::foo...42))))': &i32
[335; 348) '&&B(B(A(42)))': &&B<B<A<i32>>>
[336; 348) '&B(B(A(42)))': &B<B<A<i32>>>
[337; 338) 'B': B<B<A<i32>>>(T) -> B<T>
[337; 348) 'B(B(A(42)))': B<B<A<i32>>>
[339; 340) 'B': B<A<i32>>(T) -> B<T>
[339; 347) 'B(A(42))': B<A<i32>>
[341; 342) 'A': A<i32>(T) -> A<T>
[341; 346) 'A(42)': A<i32>
[343; 345) '42': i32
"###
[151; 174) '{ ... }': &T
[161; 168) '&self.0': &T
[162; 166) 'self': &A<T>
[162; 168) 'self.0': T
[255; 259) 'self': &B<T>
[278; 301) '{ ... }': &T
[288; 295) '&self.0': &T
[289; 293) 'self': &B<T>
[289; 295) 'self.0': T
[315; 353) '{ ...))); }': ()
[325; 326) 't': &i32
[329; 335) 'A::foo': fn foo<i32>(&A<T>) -> &T
[329; 350) 'A::foo...42))))': &i32
[336; 349) '&&B(B(A(42)))': &&B<B<A<i32>>>
[337; 349) '&B(B(A(42)))': &B<B<A<i32>>>
[338; 339) 'B': B<B<A<i32>>>(T) -> B<T>
[338; 349) 'B(B(A(42)))': B<B<A<i32>>>
[340; 341) 'B': B<A<i32>>(T) -> B<T>
[340; 348) 'B(A(42))': B<A<i32>>
[342; 343) 'A': A<i32>(T) -> A<T>
[342; 347) 'A(42)': A<i32>
[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<T>
[90; 98) 'loop { }': !
[95; 98) '{ }': ()
[118; 146) '{ ...e(); }': ()
@ -1923,8 +1922,7 @@ fn test() {
}
"#),
@r###"
[76; 100) '{ ... }': !
[76; 100) '{ ... }': Gen<T>
[86; 94) 'loop { }': !
[91; 94) '{ }': ()
[114; 149) '{ ...e(); }': ()
@ -1955,8 +1953,7 @@ fn test() {
}
"#),
@r###"
[102; 126) '{ ... }': !
[102; 126) '{ ... }': Gen<u32, T>
[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<T>(x: T) -> T {
}
fn clone<T>(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<u32>(T) -> T
[102; 107) 'id(y)': u32
[105; 106) 'y': u32
[117; 118) 'x': bool
[127; 132) 'clone': fn clone<bool>(&T) -> T
[127; 135) 'clone(z)': bool
[133; 134) 'z': &bool
[141; 151) 'id::<i128>': fn id<i128>(T) -> T
[141; 154) 'id::<i128>(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<u32>(T) -> T
[103; 108) 'id(y)': u32
[106; 107) 'y': u32
[118; 119) 'x': bool
[128; 133) 'clone': fn clone<bool>(&T) -> T
[128; 136) 'clone(z)': bool
[134; 135) 'z': &bool
[142; 152) 'id::<i128>': fn id<i128>(T) -> T
[142; 155) 'id::<i128>(1)': i128
[153; 154) '1': i128
"###
);
}
@ -3404,7 +3401,7 @@ impl S {
}
fn test(s: Arc<S>) {
(*s, s.foo())<|>
(*s, s.foo())<|>;
}
"#,
);
@ -3488,7 +3485,7 @@ impl S {
}
fn test(s: Arc<S>) {
(*s, s.foo())<|>
(*s, s.foo())<|>;
}
"#,
);

View file

@ -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<T> { a: T }
fn f<T>(_: &[T]) -> T { loop {} }
fn g<T>(_: S<&[T]>) -> T { loop {} }
fn gen<T>() -> *mut [T; 2] { loop {} }
fn test1<U>() -> *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<U>() -> *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<u8>(&[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<u8>(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