From 9d72b14cfe3606e9c55e488d74568471f981bb3d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 11 Aug 2019 13:52:34 +0200 Subject: Normalize assoc types in more places --- crates/ra_hir/src/ty/infer.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'crates/ra_hir/src/ty/infer.rs') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 74fc77cfb..675df4a22 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -412,11 +412,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ty } + /// Recurses through the given type, normalizing associated types mentioned + /// in it by replacing them by type variables and registering obligations to + /// resolve later. This should be done once for every type we get from some + /// type annotation (e.g. from a let type annotation, field type or function + /// call). `make_ty` handles this already, but e.g. for field types we need + /// to do it as well. fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { + let ty = self.resolve_ty_as_possible(&mut vec![], ty); ty.fold(&mut |ty| match ty { Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), Ty::UnselectedProjection(proj_ty) => { - // FIXME + // FIXME use Chalk's unselected projection support Ty::UnselectedProjection(proj_ty) } _ => ty, @@ -569,6 +576,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); let ty = ty.subst(&substs); let ty = self.insert_type_vars(ty); + let ty = self.normalize_associated_types_in(ty); Some(ty) } Resolution::LocalBinding(pat) => { @@ -690,6 +698,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) .map_or(Ty::Unknown, |field| field.ty(self.db)) .subst(&substs); + let expected_ty = self.normalize_associated_types_in(expected_ty); self.infer_pat(subpat, &expected_ty, default_bm); } @@ -717,6 +726,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); let expected_ty = matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); + let expected_ty = self.normalize_associated_types_in(expected_ty); self.infer_pat(subpat.pat, &expected_ty, default_bm); } @@ -947,9 +957,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.unify(&expected_receiver_ty, &actual_receiver_ty); let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); - for (arg, param) in args.iter().zip(param_iter) { - self.infer_expr(*arg, &Expectation::has_type(param)); + for (arg, param_ty) in args.iter().zip(param_iter) { + let param_ty = self.normalize_associated_types_in(param_ty); + self.infer_expr(*arg, &Expectation::has_type(param_ty)); } + let ret_ty = self.normalize_associated_types_in(ret_ty); ret_ty } @@ -1040,9 +1052,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }; self.register_obligations_for_call(&callee_ty); let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); - for (arg, param) in args.iter().zip(param_iter) { - self.infer_expr(*arg, &Expectation::has_type(param)); + for (arg, param_ty) in args.iter().zip(param_iter) { + let param_ty = self.normalize_associated_types_in(param_ty); + self.infer_expr(*arg, &Expectation::has_type(param_ty)); } + let ret_ty = self.normalize_associated_types_in(ret_ty); ret_ty } Expr::MethodCall { receiver, args, method_name, generic_args } => self @@ -1140,7 +1154,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { _ => None, }) .unwrap_or(Ty::Unknown); - self.insert_type_vars(ty) + let ty = self.insert_type_vars(ty); + self.normalize_associated_types_in(ty) } Expr::Await { expr } => { let inner_ty = self.infer_expr(*expr, &Expectation::none()); -- cgit v1.2.3