Handle impl Trait more correctly

When calling a function, argument-position impl Trait is transparent; same for
return-position impl Trait when inside the function. So in these cases, we need
to represent that type not by `Ty::Opaque`, but by a type variable that can be
unified with whatever flows into there.
This commit is contained in:
Florian Diebold 2019-12-15 18:56:38 +01:00
parent ac961b2614
commit 6e1c2d0df8
3 changed files with 56 additions and 1 deletions

View file

@ -274,6 +274,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.normalize_associated_types_in(ty) self.normalize_associated_types_in(ty)
} }
/// Replaces `impl Trait` in `ty` by type variables and obligations for
/// those variables. This is done for function arguments when calling a
/// function, and for return types when inside the function body, i.e. in
/// the cases where the `impl Trait` is 'transparent'. In other cases, `impl
/// Trait` is represented by `Ty::Opaque`.
fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty {
Ty::Opaque(preds) => {
let var = self.table.new_type_var();
let var_subst = Substs::builder(1).push(var.clone()).build();
self.obligations.extend(
preds
.iter()
.map(|pred| pred.clone().subst_bound_vars(&var_subst))
.filter_map(Obligation::from_predicate),
);
var
}
_ => ty,
})
}
/// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty { match ty {
@ -414,7 +436,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.infer_pat(*pat, &ty, BindingMode::default()); self.infer_pat(*pat, &ty, BindingMode::default());
} }
self.return_ty = self.make_ty(&data.ret_type); let return_ty = self.make_ty(&data.ret_type);
self.return_ty = self.insert_vars_for_impl_trait(return_ty);
} }
fn infer_body(&mut self) { fn infer_body(&mut self) {

View file

@ -613,6 +613,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
continue; continue;
} }
let param_ty = self.insert_vars_for_impl_trait(param_ty);
let param_ty = self.normalize_associated_types_in(param_ty); let param_ty = self.normalize_associated_types_in(param_ty);
self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
} }

View file

@ -1509,6 +1509,37 @@ fn test() -> impl Trait<i32> {
} }
"#, true), "#, true),
@r###" @r###"
[27; 28) 'x': impl Trait<u32>
[47; 58) '{ loop {} }': ()
[49; 56) 'loop {}': !
[54; 56) '{}': ()
[69; 70) 'x': impl Trait<T>
[92; 103) '{ loop {} }': T
[94; 101) 'loop {}': !
[99; 101) '{}': ()
[172; 183) '{ loop {} }': T
[174; 181) 'loop {}': !
[179; 181) '{}': ()
[214; 310) '{ ...t()) }': S<i32>
[224; 226) 's1': S<u32>
[229; 230) 'S': S<u32>(T) -> S<T>
[229; 241) 'S(default())': S<u32>
[231; 238) 'default': fn default<u32>() -> T
[231; 240) 'default()': u32
[247; 250) 'foo': fn foo(impl Trait<u32>) -> ()
[247; 254) 'foo(s1)': ()
[251; 253) 's1': S<u32>
[264; 265) 'x': i32
[273; 276) 'bar': fn bar<i32>(impl Trait<T>) -> T
[273; 290) 'bar(S(...lt()))': i32
[277; 278) 'S': S<i32>(T) -> S<T>
[277; 289) 'S(default())': S<i32>
[279; 286) 'default': fn default<i32>() -> T
[279; 288) 'default()': i32
[296; 297) 'S': S<i32>(T) -> S<T>
[296; 308) 'S(default())': S<i32>
[298; 305) 'default': fn default<i32>() -> T
[298; 307) 'default()': i32
"### "###
); );
} }