From 6e1c2d0df89a390be33c81b6e03a5ad352763593 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 15 Dec 2019 18:56:38 +0100 Subject: 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. --- crates/ra_hir_ty/src/infer.rs | 25 ++++++++++++++++++++++++- crates/ra_hir_ty/src/infer/expr.rs | 1 + crates/ra_hir_ty/src/tests/traits.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index af42854cc..1aa1330a6 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs @@ -274,6 +274,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { 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. fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty { @@ -414,7 +436,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { 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) { diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 2e3cdd53a..924ad3e81 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -613,6 +613,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { continue; } + let param_ty = self.insert_vars_for_impl_trait(param_ty); let param_ty = self.normalize_associated_types_in(param_ty); self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); } diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index a926d01e5..d8673c90d 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1509,6 +1509,37 @@ fn test() -> impl Trait { } "#, true), @r###" + [27; 28) 'x': impl Trait + [47; 58) '{ loop {} }': () + [49; 56) 'loop {}': ! + [54; 56) '{}': () + [69; 70) 'x': impl Trait + [92; 103) '{ loop {} }': T + [94; 101) 'loop {}': ! + [99; 101) '{}': () + [172; 183) '{ loop {} }': T + [174; 181) 'loop {}': ! + [179; 181) '{}': () + [214; 310) '{ ...t()) }': S + [224; 226) 's1': S + [229; 230) 'S': S(T) -> S + [229; 241) 'S(default())': S + [231; 238) 'default': fn default() -> T + [231; 240) 'default()': u32 + [247; 250) 'foo': fn foo(impl Trait) -> () + [247; 254) 'foo(s1)': () + [251; 253) 's1': S + [264; 265) 'x': i32 + [273; 276) 'bar': fn bar(impl Trait) -> T + [273; 290) 'bar(S(...lt()))': i32 + [277; 278) 'S': S(T) -> S + [277; 289) 'S(default())': S + [279; 286) 'default': fn default() -> T + [279; 288) 'default()': i32 + [296; 297) 'S': S(T) -> S + [296; 308) 'S(default())': S + [298; 305) 'default': fn default() -> T + [298; 307) 'default()': i32 "### ); } -- cgit v1.2.3