diff options
| author | Florian Diebold <flodiebold@gmail.com> | 2022-02-25 15:46:02 +0100 |
|---|---|---|
| committer | Florian Diebold <flodiebold@gmail.com> | 2022-02-25 15:46:02 +0100 |
| commit | 6fc3d3aa4cbf637d748c60cfdbb98b5f6a040576 (patch) | |
| tree | 1bdcc57c926fef4d7fad9175b710389f50a15766 | |
| parent | 187e6bacac2c01b9bc28f8c0480d807434abd4f7 (diff) | |
| download | rust-6fc3d3aa4cbf637d748c60cfdbb98b5f6a040576.tar.gz rust-6fc3d3aa4cbf637d748c60cfdbb98b5f6a040576.zip | |
Avoid autoderef coercions leaking if they don't apply
| -rw-r--r-- | crates/hir_ty/src/infer/coerce.rs | 3 | ||||
| -rw-r--r-- | crates/hir_ty/src/tests/coercion.rs | 39 |
2 files changed, 42 insertions, 0 deletions
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 036941c0df0..c24772f29b4 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs @@ -259,6 +259,8 @@ impl<'a> InferenceContext<'a> { // 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 @@ impl<'a> InferenceContext<'a> { 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); } diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index dd3b86f0503..c0dddb608ea 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs @@ -243,6 +243,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( r" |
