]> git.lizzy.rs Git - rust.git/commitdiff
Avoid autoderef coercions leaking if they don't apply
authorFlorian Diebold <flodiebold@gmail.com>
Fri, 25 Feb 2022 14:46:02 +0000 (15:46 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Fri, 25 Feb 2022 14:46:02 +0000 (15:46 +0100)
crates/hir_ty/src/infer/coerce.rs
crates/hir_ty/src/tests/coercion.rs

index 036941c0df0d5e372f7f3d178a75e9c1f8920cf1..c24772f29b428709973ee7a9b3675cfbd2e95737 100644 (file)
@@ -259,6 +259,8 @@ fn coerce_ref(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceRe
         // details of coercion errors though, so I think it's useful to leave
         // the structure like it is.
 
+        let snapshot = self.table.snapshot();
+
         let mut autoderef = Autoderef::new(&mut self.table, from_ty.clone());
         let mut first_error = None;
         let mut found = None;
@@ -315,6 +317,7 @@ fn coerce_ref(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> CoerceRe
         let InferOk { value: ty, goals } = match found {
             Some(d) => d,
             None => {
+                self.table.rollback_to(snapshot);
                 let err = first_error.expect("coerce_borrowed_pointer had no error");
                 return Err(err);
             }
index dd3b86f05033ad8d25216bebb22b44eebc4fdb0c..c0dddb608ea394e75c4c057aa01c9db2c00e280d 100644 (file)
@@ -242,6 +242,45 @@ fn test() {
     );
 }
 
+#[test]
+fn coerce_autoderef_implication_1() {
+    check_no_mismatches(
+        r"
+//- minicore: deref
+struct Foo<T>;
+impl core::ops::Deref for Foo<u32> { type Target = (); }
+
+fn takes_ref_foo<T>(x: &Foo<T>) {}
+fn test() {
+    let foo = Foo;
+      //^^^ type: Foo<{unknown}>
+    takes_ref_foo(&foo);
+
+    let foo = Foo;
+      //^^^ type: Foo<u32>
+    let _: &() = &foo;
+}",
+    );
+}
+
+#[test]
+fn coerce_autoderef_implication_2() {
+    check(
+        r"
+//- minicore: deref
+struct Foo<T>;
+impl core::ops::Deref for Foo<u32> { type Target = (); }
+
+fn takes_ref_foo<T>(x: &Foo<T>) {}
+fn test() {
+    let foo = Foo;
+      //^^^ type: Foo<{unknown}>
+    let _: &u32 = &Foo;
+                //^^^^ expected &u32, got &Foo<{unknown}>
+}",
+    );
+}
+
 #[test]
 fn closure_return_coerce() {
     check_no_mismatches(