-
Notifications
You must be signed in to change notification settings - Fork 12.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #57885 - arielb1:xform-probe, r=nikomatsakis
Avoid committing to autoderef in object method probing This fixes the "leak" introduced in #57835 (see test for details, also apparently #54252 had no tests for the "leaks" that were fixed in it, so go ahead and add one). Maybe beta-nominating because regression, but I'm against landing things on beta we don't have to. r? @nikomatsakis
- Loading branch information
Showing
5 changed files
with
402 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
src/test/run-pass/methods/method-probe-no-guessing-dyn-trait.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Check that method matching does not make "guesses" depending on | ||
// Deref impls that don't eventually end up being picked. | ||
|
||
use std::ops::Deref; | ||
|
||
// An impl with less derefs will get called over an impl with more derefs, | ||
// so `(t: Foo<_>).my_fn()` will use `<Foo<u32> as MyTrait1>::my_fn(t)`, | ||
// and does *not* force the `_` to equal `()`, because the Deref impl | ||
// was *not* used. | ||
|
||
trait MyTrait1 { | ||
fn my_fn(&self) {} | ||
} | ||
|
||
impl MyTrait1 for Foo<u32> {} | ||
|
||
struct Foo<T>(T); | ||
|
||
impl Deref for Foo<()> { | ||
type Target = dyn MyTrait1 + 'static; | ||
fn deref(&self) -> &(dyn MyTrait1 + 'static) { | ||
panic!() | ||
} | ||
} | ||
|
||
// ...but if there is no impl with less derefs, the "guess" will be | ||
// forced, so `(t: Bar<_>).my_fn2()` is `<dyn MyTrait2 as MyTrait2>::my_fn2(*t)`, | ||
// and because the deref impl is used, the `_` is forced to equal `u8`. | ||
|
||
trait MyTrait2 { | ||
fn my_fn2(&self) {} | ||
} | ||
|
||
impl MyTrait2 for u32 {} | ||
struct Bar<T>(T, u32); | ||
impl Deref for Bar<u8> { | ||
type Target = dyn MyTrait2 + 'static; | ||
fn deref(&self) -> &(dyn MyTrait2 + 'static) { | ||
&self.1 | ||
} | ||
} | ||
|
||
// actually invoke things | ||
|
||
fn main() { | ||
let mut foo: Option<Foo<_>> = None; | ||
let mut bar: Option<Bar<_>> = None; | ||
let mut first_iter = true; | ||
loop { | ||
if !first_iter { | ||
foo.as_ref().unwrap().my_fn(); | ||
bar.as_ref().unwrap().my_fn2(); | ||
break; | ||
} | ||
foo = Some(Foo(0)); | ||
bar = Some(Bar(Default::default(), 0)); | ||
first_iter = false; | ||
} | ||
} |
177 changes: 177 additions & 0 deletions
177
src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize, unsized_locals)] | ||
|
||
// This tests a few edge-cases around `arbitrary_self_types`. Most specifically, | ||
// it checks that the `ObjectCandidate` you get from method matching can't | ||
// match a trait with the same DefId as a supertrait but a bad type parameter. | ||
|
||
use std::marker::PhantomData; | ||
|
||
mod internal { | ||
use std::ops::{CoerceUnsized, Deref, DispatchFromDyn}; | ||
use std::marker::{PhantomData, Unsize}; | ||
|
||
pub struct Smaht<T: ?Sized, MISC>(pub Box<T>, pub PhantomData<MISC>); | ||
|
||
impl<T: ?Sized, MISC> Deref for Smaht<T, MISC> { | ||
type Target = T; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.0 | ||
} | ||
} | ||
impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> CoerceUnsized<Smaht<U, MISC>> | ||
for Smaht<T, MISC> | ||
{} | ||
impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> DispatchFromDyn<Smaht<U, MISC>> | ||
for Smaht<T, MISC> | ||
{} | ||
|
||
pub trait Foo: X<u32> {} | ||
pub trait X<T> { | ||
fn foo(self: Smaht<Self, T>) -> T; | ||
} | ||
|
||
impl X<u32> for () { | ||
fn foo(self: Smaht<Self, u32>) -> u32 { | ||
0 | ||
} | ||
} | ||
|
||
pub trait Marker {} | ||
impl Marker for dyn Foo {} | ||
impl<T: Marker + ?Sized> X<u64> for T { | ||
fn foo(self: Smaht<Self, u64>) -> u64 { | ||
1 | ||
} | ||
} | ||
|
||
impl Deref for dyn Foo { | ||
type Target = (); | ||
fn deref(&self) -> &() { &() } | ||
} | ||
|
||
impl Foo for () {} | ||
} | ||
|
||
pub trait FinalFoo { | ||
fn foo(&self) -> u8; | ||
} | ||
|
||
impl FinalFoo for () { | ||
fn foo(&self) -> u8 { 0 } | ||
} | ||
|
||
mod nuisance_foo { | ||
pub trait NuisanceFoo { | ||
fn foo(self); | ||
} | ||
|
||
impl<T: ?Sized> NuisanceFoo for T { | ||
fn foo(self) {} | ||
} | ||
} | ||
|
||
|
||
fn objectcandidate_impl() { | ||
let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); | ||
let x: internal::Smaht<dyn internal::Foo, u32> = x; | ||
|
||
// This picks `<dyn internal::Foo as X<u32>>::foo` via `ObjectCandidate`. | ||
// | ||
// The `TraitCandidate` is not relevant because `X` is not in scope. | ||
let z = x.foo(); | ||
|
||
// Observe the type of `z` is `u32` | ||
let _seetype: () = z; //~ ERROR mismatched types | ||
//~| expected (), found u32 | ||
} | ||
|
||
fn traitcandidate_impl() { | ||
use internal::X; | ||
|
||
let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); | ||
let x: internal::Smaht<dyn internal::Foo, u64> = x; | ||
|
||
// This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`. | ||
// | ||
// The `ObjectCandidate` does not apply, as it only applies to | ||
// `X<u32>` (and not `X<u64>`). | ||
let z = x.foo(); | ||
|
||
// Observe the type of `z` is `u64` | ||
let _seetype: () = z; //~ ERROR mismatched types | ||
//~| expected (), found u64 | ||
} | ||
|
||
fn traitcandidate_impl_with_nuisance() { | ||
use internal::X; | ||
use nuisance_foo::NuisanceFoo; | ||
|
||
let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); | ||
let x: internal::Smaht<dyn internal::Foo, u64> = x; | ||
|
||
// This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`. | ||
// | ||
// The `ObjectCandidate` does not apply, as it only applies to | ||
// `X<u32>` (and not `X<u64>`). | ||
// | ||
// The NuisanceFoo impl has the same priority as the `X` impl, | ||
// so we get a conflict. | ||
let z = x.foo(); //~ ERROR multiple applicable items in scope | ||
} | ||
|
||
|
||
fn neither_impl() { | ||
let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); | ||
let x: internal::Smaht<dyn internal::Foo, u64> = x; | ||
|
||
// This can't pick the `TraitCandidate` impl, because `Foo` is not | ||
// imported. However, this also can't pick the `ObjectCandidate` | ||
// impl, because it only applies to `X<u32>` (and not `X<u64>`). | ||
// | ||
// Therefore, neither of the candidates is applicable, and we pick | ||
// the `FinalFoo` impl after another deref, which will return `u8`. | ||
let z = x.foo(); | ||
|
||
// Observe the type of `z` is `u8` | ||
let _seetype: () = z; //~ ERROR mismatched types | ||
//~| expected (), found u8 | ||
} | ||
|
||
fn both_impls() { | ||
use internal::X; | ||
|
||
let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); | ||
let x: internal::Smaht<dyn internal::Foo, u32> = x; | ||
|
||
// This can pick both the `TraitCandidate` and the `ObjectCandidate` impl. | ||
// | ||
// However, the `ObjectCandidate` is considered an "inherent candidate", | ||
// and therefore has priority over both the `TraitCandidate` as well as | ||
// any other "nuisance" candidate" (if present). | ||
let z = x.foo(); | ||
|
||
// Observe the type of `z` is `u32` | ||
let _seetype: () = z; //~ ERROR mismatched types | ||
//~| expected (), found u32 | ||
} | ||
|
||
|
||
fn both_impls_with_nuisance() { | ||
// Similar to the `both_impls` example, except with a nuisance impl to | ||
// make sure the `ObjectCandidate` indeed has a higher priority. | ||
|
||
use internal::X; | ||
use nuisance_foo::NuisanceFoo; | ||
|
||
let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); | ||
let x: internal::Smaht<dyn internal::Foo, u32> = x; | ||
let z = x.foo(); | ||
|
||
// Observe the type of `z` is `u32` | ||
let _seetype: () = z; //~ ERROR mismatched types | ||
//~| expected (), found u32 | ||
} | ||
|
||
fn main() { | ||
} |
72 changes: 72 additions & 0 deletions
72
src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
error[E0308]: mismatched types | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:85:24 | ||
| | ||
LL | let _seetype: () = z; //~ ERROR mismatched types | ||
| ^ expected (), found u32 | ||
| | ||
= note: expected type `()` | ||
found type `u32` | ||
|
||
error[E0308]: mismatched types | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:102:24 | ||
| | ||
LL | let _seetype: () = z; //~ ERROR mismatched types | ||
| ^ expected (), found u64 | ||
| | ||
= note: expected type `()` | ||
found type `u64` | ||
|
||
error[E0034]: multiple applicable items in scope | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:120:15 | ||
| | ||
LL | let z = x.foo(); //~ ERROR multiple applicable items in scope | ||
| ^^^ multiple `foo` found | ||
| | ||
note: candidate #1 is defined in an impl of the trait `internal::X` for the type `_` | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:43:9 | ||
| | ||
LL | fn foo(self: Smaht<Self, u64>) -> u64 { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_` | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 | ||
| | ||
LL | fn foo(self) {} | ||
| ^^^^^^^^^^^^ | ||
note: candidate #3 is defined in the trait `FinalFoo` | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5 | ||
| | ||
LL | fn foo(&self) -> u8; | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
= help: to disambiguate the method call, write `FinalFoo::foo(x)` instead | ||
|
||
error[E0308]: mismatched types | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24 | ||
| | ||
LL | let _seetype: () = z; //~ ERROR mismatched types | ||
| ^ expected (), found u8 | ||
| | ||
= note: expected type `()` | ||
found type `u8` | ||
|
||
error[E0308]: mismatched types | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:155:24 | ||
| | ||
LL | let _seetype: () = z; //~ ERROR mismatched types | ||
| ^ expected (), found u32 | ||
| | ||
= note: expected type `()` | ||
found type `u32` | ||
|
||
error[E0308]: mismatched types | ||
--> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:172:24 | ||
| | ||
LL | let _seetype: () = z; //~ ERROR mismatched types | ||
| ^ expected (), found u32 | ||
| | ||
= note: expected type `()` | ||
found type `u32` | ||
|
||
error: aborting due to 6 previous errors | ||
|
||
Some errors occurred: E0034, E0308. | ||
For more information about an error, try `rustc --explain E0034`. |
Oops, something went wrong.