]> git.lizzy.rs Git - rust.git/commitdiff
Normalize assoc types in more places
authorFlorian Diebold <flodiebold@gmail.com>
Sun, 11 Aug 2019 11:52:34 +0000 (13:52 +0200)
committerFlorian Diebold <flodiebold@gmail.com>
Mon, 12 Aug 2019 19:43:00 +0000 (21:43 +0200)
crates/ra_hir/src/ty/infer.rs
crates/ra_hir/src/ty/tests.rs

index 74fc77cfbc90f25dcf9af79c06460c0fc9998022..675df4a22f40afe72aeb8a3f7bee2fb66e23ea18 100644 (file)
@@ -412,11 +412,18 @@ fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
         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 @@ fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId)
                 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 @@ fn infer_tuple_struct_pat(
                 .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 @@ fn infer_struct_pat(
             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 @@ fn infer_method_call(
         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 @@ fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 };
                 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 @@ fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                     _ => 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());
index 01b3583359579ebe4a1fef69a590e4fde56f24c1..e6a09cc6738cd65e90c8aa17f2a0acc54bb3c089 100644 (file)
@@ -2515,10 +2515,10 @@ fn test<T: Iterable>() {
         @r###"
    ⋮
    ⋮[108; 227) '{     ...ter; }': ()
-   ⋮[118; 119) 'x': <S as Iterable>::Item
-   ⋮[145; 146) '1': <S as Iterable>::Item
-   ⋮[156; 157) 'y': <T as Iterable>::Item
-   ⋮[183; 192) 'no_matter': <T as Iterable>::Item
+   ⋮[118; 119) 'x': u32
+   ⋮[145; 146) '1': u32
+   ⋮[156; 157) 'y': {unknown}
+   ⋮[183; 192) 'no_matter': {unknown}
    ⋮[202; 203) 'z': {unknown}
    ⋮[215; 224) 'no_matter': {unknown}
     "###
@@ -2552,9 +2552,9 @@ fn test() {
    ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown}
    ⋮[205; 212) 'foo1(S)': {unknown}
    ⋮[210; 211) 'S': S
-   ⋮[222; 223) 'y': <S as Iterable>::Item
+   ⋮[222; 223) 'y': u32
    ⋮[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
-   ⋮[226; 233) 'foo2(S)': <S as Iterable>::Item
+   ⋮[226; 233) 'foo2(S)': u32
    ⋮[231; 232) 'S': S
     "###
     );