Implement type inference for tuples and refs

This commit is contained in:
Marcus Klaas de Vries 2019-01-15 18:47:37 +01:00 committed by Aleksey Kladov
parent afaa26636e
commit 5648dcd36e
3 changed files with 58 additions and 7 deletions

View File

@ -36,7 +36,7 @@ use crate::{
db::HirDatabase,
type_ref::{TypeRef, Mutability},
name::KnownName,
expr::{Body, Expr, Literal, ExprId, PatId, UnaryOp, BinaryOp, Statement},
expr::{Body, Expr, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement},
};
/// The ID of a type variable.
@ -872,6 +872,35 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
}
// FIXME: Expectation should probably contain a reference to a Ty instead of
// a Ty itself
fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty {
let body = Arc::clone(&self.body); // avoid borrow checker problem
match (&body[pat], &expected.ty) {
(Pat::Tuple(ref args), &Ty::Tuple(ref tuple_args))
if args.len() == tuple_args.len() =>
{
for (&pat, ty) in args.iter().zip(tuple_args.iter()) {
// FIXME: can we do w/o cloning?
self.infer_pat(pat, &Expectation::has_type(ty.clone()));
}
}
(&Pat::Ref { pat, mutability }, &Ty::Ref(ref sub_ty, ty_mut))
if mutability == ty_mut =>
{
self.infer_pat(pat, &Expectation::has_type((&**sub_ty).clone()));
}
// TODO: implement more
(_, ref _expected_ty) => {}
};
// use a new type variable if we got Ty::Unknown here
let ty = self.insert_type_vars_shallow(expected.ty.clone());
self.unify(&ty, &expected.ty);
let ty = self.resolve_ty_as_possible(ty);
self.write_pat_ty(pat, ty.clone());
ty
}
fn infer_expr(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
let body = Arc::clone(&self.body); // avoid borrow checker problem
let ty = match &body[expr] {
@ -1168,9 +1197,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
decl_ty
};
// TODO: walk the pattern here?
self.write_pat_ty(*pat, ty);
self.infer_pat(*pat, &Expectation::has_type(ty))?;
}
Statement::Expr(expr) => {
self.infer_expr(*expr, &Expectation::none());
@ -1191,9 +1218,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let ty = self.make_ty(type_ref);
let ty = self.insert_type_vars(ty);
// TODO: walk pattern?
self.write_pat_ty(*pat, ty);
self.infer_pat(*pat, &Expectation::has_type(ty))?;
}
self.return_ty = {
let ty = self.make_ty(signature.ret_type());

View File

@ -362,11 +362,22 @@ fn test(x: &str, y: isize) {
fn infer_pattern() {
check_inference(
r#"
enum E { A { x: usize }, B }
fn test(x: &i32) {
let y = x;
let &z = x;
let a = z;
let (c, d) = (1, "hello");
let e = E::A { x: 3 };
if let E::A { x: x } = e {
x
};
match e {
E::A { x } => x,
E::B => 1,
};
}
"#,
"pattern.txt",

View File

@ -0,0 +1,15 @@
[9; 10) 'x': &i32
[18; 98) '{ ...o"); }': ()
[28; 29) 'y': &i32
[32; 33) 'x': &i32
[43; 45) '&z': &i32
[44; 45) 'z': i32
[48; 49) 'x': &i32
[59; 60) 'a': i32
[63; 64) 'z': i32
[74; 80) '(c, d)': (i32, &str)
[75; 76) 'c': i32
[78; 79) 'd': &str
[83; 95) '(1, "hello")': (i32, &str)
[84; 85) '1': i32
[87; 94) '"hello"': &str