Implement type inference for tuples and refs
This commit is contained in:
parent
afaa26636e
commit
5648dcd36e
@ -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());
|
||||
|
@ -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",
|
||||
|
15
crates/ra_hir/src/ty/tests/data/pattern.txt
Normal file
15
crates/ra_hir/src/ty/tests/data/pattern.txt
Normal 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
|
Loading…
x
Reference in New Issue
Block a user