Make pattern inference work w/o proper expecations

This commit is contained in:
Marcus Klaas de Vries 2019-01-17 10:54:47 +01:00 committed by Aleksey Kladov
parent be1b4034a5
commit 9433a108cf
2 changed files with 63 additions and 35 deletions

View File

@ -911,7 +911,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
return Ty::Unknown;
};
// walk subpats
if fields.len() != sub_pats.len() {
return Ty::Unknown;
}
@ -944,44 +943,49 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty
}
// FIXME: Expectation should probably contain a reference to a Ty instead of
// a Ty itself
// TODO: Expectation should probably contain a Cow pointer to Ty?
// so that we can make new expectations of subtypes cheaply
fn infer_pat(&mut self, pat: PatId, expected: &Expectation) -> Ty {
let body = Arc::clone(&self.body); // avoid borrow checker problem
// FIXME: we can do some inference even if the expected ty isnt already
// of the right form
let ty = 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()));
}
expected.ty.clone()
let ty = match &body[pat] {
Pat::Tuple(ref args) => {
// this can probably be done without cloning/ collecting
let expectations = match expected.ty {
Ty::Tuple(ref tuple_args) if args.len() == tuple_args.len() => {
tuple_args.iter().cloned().collect()
}
_ => vec![Ty::Unknown; args.len()],
};
let inner_tys = args
.iter()
.zip(expectations.into_iter())
.map(|(&pat, ty)| self.infer_pat(pat, &Expectation::has_type(ty)))
.collect::<Vec<_>>()
.into();
Ty::Tuple(inner_tys)
}
(&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()));
expected.ty.clone()
Pat::Ref { pat, mutability } => {
let expectation = match expected.ty {
Ty::Ref(ref sub_ty, exp_mut) if *mutability == exp_mut => {
Expectation::has_type((&**sub_ty).clone())
}
_ => Expectation::none(),
};
let subty = self.infer_pat(*pat, &expectation);
Ty::Ref(subty.into(), *mutability)
}
(
&Pat::TupleStruct {
path: ref p,
args: ref sub_pats,
},
_,
) => self.infer_tuple_struct(p.as_ref(), sub_pats),
(
&Pat::Struct {
path: ref p,
args: ref fields,
},
_,
) => self.infer_struct(p.as_ref(), fields),
(_, ref _expected_ty) => expected.ty.clone(),
Pat::TupleStruct {
path: ref p,
args: ref sub_pats,
} => self.infer_tuple_struct(p.as_ref(), sub_pats),
Pat::Struct {
path: ref p,
args: ref fields,
} => self.infer_struct(p.as_ref(), fields),
_ => Ty::Unknown,
};
// use a new type variable if we got Ty::Unknown here
let ty = self.insert_type_vars_shallow(ty);

View File

@ -1,5 +1,5 @@
[9; 10) 'x': &i32
[18; 98) '{ ...o"); }': ()
[18; 259) '{ ...c }; }': ()
[28; 29) 'y': &i32
[32; 33) 'x': &i32
[43; 45) '&z': &i32
@ -13,3 +13,27 @@
[83; 95) '(1, "hello")': (i32, &str)
[84; 85) '1': i32
[87; 94) '"hello"': &str
[102; 152) 'for (e... }': ()
[106; 112) '(e, f)': ([unknown], [unknown])
[107; 108) 'e': [unknown]
[110; 111) 'f': [unknown]
[116; 125) 'some_iter': [unknown]
[126; 152) '{ ... }': ()
[140; 141) 'g': [unknown]
[144; 145) 'e': [unknown]
[158; 205) 'if let... }': ()
[165; 170) '[val]': [unknown]
[173; 176) 'opt': [unknown]
[177; 205) '{ ... }': ()
[191; 192) 'h': [unknown]
[195; 198) 'val': [unknown]
[215; 221) 'lambda': [unknown]
[224; 256) '|a: u6...b; c }': [unknown]
[225; 226) 'a': u64
[233; 234) 'b': u64
[236; 237) 'c': i32
[244; 256) '{ a + b; c }': i32
[246; 247) 'a': u64
[246; 251) 'a + b': u64
[250; 251) 'b': u64
[253; 254) 'c': i32