]> git.lizzy.rs Git - rust.git/commitdiff
Add test for #8931 and better checking
authorFlorian Diebold <flodiebold@gmail.com>
Sun, 23 May 2021 10:52:41 +0000 (12:52 +0200)
committerFlorian Diebold <flodiebold@gmail.com>
Sun, 23 May 2021 10:52:41 +0000 (12:52 +0200)
crates/hir/src/lib.rs
crates/hir_ty/src/lib.rs
crates/ide_completion/src/completions/dot.rs

index 52d72c3c529b25d3c1077df96c96d9031ffb0ecf..800101c91968f879d6b331f242bfe5ea7c3bcfb7 100644 (file)
@@ -2053,7 +2053,7 @@ pub fn iterate_path_candidates<T>(
         name: Option<&Name>,
         mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
     ) -> Option<T> {
-        let canonical = hir_ty::replace_errors_with_variables(self.ty.clone());
+        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
         let env = self.env.clone();
         let krate = krate.id;
@@ -2222,7 +2222,7 @@ fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
     }
 
     pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
-        let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone()));
+        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
         could_unify(db, self.env.clone(), &tys)
     }
 }
index 72093d75a2e03528e0fa67eaf0eedb4609e8740f..ef021978aded67a22552bbfc15737f4eabb67302 100644 (file)
@@ -43,7 +43,6 @@ macro_rules! eprintln {
     type_ref::{ConstScalar, Rawness},
     TypeParamId,
 };
-use stdx::always;
 
 use crate::{db::HirDatabase, utils::generics};
 
@@ -329,14 +328,17 @@ fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
     t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
 }
 
-pub fn replace_errors_with_variables<T>(t: T) -> Canonical<T::Result>
+/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
+/// ensures there are no unbound variables or inference variables anywhere in
+/// the `t`.
+pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T::Result>
 where
-    T: HasInterner<Interner = Interner> + Fold<Interner>,
+    T: HasInterner<Interner = Interner> + Fold<Interner> + Clone,
     T::Result: HasInterner<Interner = Interner>,
 {
     use chalk_ir::{
         fold::{Folder, SuperFold},
-        Fallible,
+        Fallible, NoSolution,
     };
     struct ErrorReplacer {
         vars: usize,
@@ -363,18 +365,88 @@ fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
 
         fn fold_inference_ty(
             &mut self,
-            var: InferenceVar,
-            kind: TyVariableKind,
+            _var: InferenceVar,
+            _kind: TyVariableKind,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Ty> {
+            if cfg!(debug_assertions) {
+                // we don't want to just panic here, because then the error message
+                // won't contain the whole thing, which would not be very helpful
+                Err(NoSolution)
+            } else {
+                Ok(TyKind::Error.intern(&Interner))
+            }
+        }
+
+        fn fold_free_var_ty(
+            &mut self,
+            _bound_var: BoundVar,
             _outer_binder: DebruijnIndex,
         ) -> Fallible<Ty> {
-            always!(false);
-            Ok(TyKind::InferenceVar(var, kind).intern(&Interner))
+            if cfg!(debug_assertions) {
+                // we don't want to just panic here, because then the error message
+                // won't contain the whole thing, which would not be very helpful
+                Err(NoSolution)
+            } else {
+                Ok(TyKind::Error.intern(&Interner))
+            }
+        }
+
+        fn fold_inference_const(
+            &mut self,
+            _ty: Ty,
+            _var: InferenceVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Const> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(dummy_usize_const())
+            }
+        }
+
+        fn fold_free_var_const(
+            &mut self,
+            _ty: Ty,
+            _bound_var: BoundVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Const> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(dummy_usize_const())
+            }
+        }
+
+        fn fold_inference_lifetime(
+            &mut self,
+            _var: InferenceVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Lifetime> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(static_lifetime())
+            }
+        }
+
+        fn fold_free_var_lifetime(
+            &mut self,
+            _bound_var: BoundVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Lifetime> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(static_lifetime())
+            }
         }
     }
     let mut error_replacer = ErrorReplacer { vars: 0 };
-    let value = t
-        .fold_with(&mut error_replacer, DebruijnIndex::INNERMOST)
-        .expect("fold failed unexpectedly");
+    let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
+        Ok(t) => t,
+        Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
+    };
     let kinds = (0..error_replacer.vars).map(|_| {
         chalk_ir::CanonicalVarKind::new(
             chalk_ir::VariableKind::Ty(TyVariableKind::General),
index 7e4efe5898149ee8aa98c8a84783215ee36b3b86..1bff559365be9bc72595c741b591295f9fb023a0 100644 (file)
@@ -454,4 +454,33 @@ fn baz() {
             "#]],
         );
     }
+
+    #[test]
+    fn issue_8931() {
+        check(
+            r#"
+#[lang = "fn_once"]
+trait FnOnce<Args> {
+    type Output;
+}
+struct S;
+
+struct Foo;
+impl Foo {
+    fn foo(&self) -> &[u8] { loop {} }
+}
+
+impl S {
+    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
+    }
+
+    fn f(&mut self, v: Foo) {
+        self.indented(|this| v.$0)
+    }
+}
+        "#,
+            expect![[r#"
+            "#]],
+        );
+    }
 }