mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 04:04:06 +00:00
Test exploring the interactions between all of the different kinds of method collisions I could imagine.
The different impls are all guarded by cfg-flags, and the revisions could be used to cover the full power-set of combinations. (I only included 20 of the possible 32 cases here; the null-set is not interesting, and the remaining 11 all yielded ambiguous method resolution errors which did not mix well with this testing strategy; I'm not trying to check UI for the resolution diagnostics; I'm trying to create checkpoint of current resolution semantics when compilation succeeds.)
This commit is contained in:
parent
ff4665f45f
commit
532332fa8f
190
src/test/ui/methods/method-lookup-order.rs
Normal file
190
src/test/ui/methods/method-lookup-order.rs
Normal file
@ -0,0 +1,190 @@
|
||||
// ignore-tidy-linelength
|
||||
|
||||
// run-pass
|
||||
|
||||
// There are five cfg's below. I explored the set of all non-empty combinations
|
||||
// of the below five cfg's, which is 2^5 - 1 = 31 combinations.
|
||||
//
|
||||
// Of the 31, 11 resulted in ambiguous method resolutions; while it may be good
|
||||
// to have a test for all of the eleven variations of that error, I am not sure
|
||||
// this particular test is the best way to encode it. So they are skipped in
|
||||
// this revisions list (but not in the expansion mapping the binary encoding to
|
||||
// the corresponding cfg flags).
|
||||
//
|
||||
// Notable, here are the cases that will be incompatible if something does not override them first:
|
||||
// {bar_for_foo, valbar_for_et_foo}: these are higher precedent than the `&mut self` method on `Foo`, and so no case matching bx1x1x is included.
|
||||
// {mutbar_for_foo, valbar_for_etmut_foo} (which are lower precedent than the inherent `&mut self` method on `Foo`; e.g. b10101 *is* included.
|
||||
|
||||
// revisions: b00001 b00010 b00011 b00100 b00101 b00110 b00111 b01000 b01001 b01100 b01101 b10000 b10001 b10010 b10011 b10101 b10111 b11000 b11001 b11101
|
||||
|
||||
//[b00001]compile-flags: --cfg inherent_mut
|
||||
//[b00010]compile-flags: --cfg bar_for_foo
|
||||
//[b00011]compile-flags: --cfg inherent_mut --cfg bar_for_foo
|
||||
//[b00100]compile-flags: --cfg mutbar_for_foo
|
||||
//[b00101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo
|
||||
//[b00110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo
|
||||
//[b00111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo
|
||||
//[b01000]compile-flags: --cfg valbar_for_et_foo
|
||||
//[b01001]compile-flags: --cfg inherent_mut --cfg valbar_for_et_foo
|
||||
//[b01010]compile-flags: --cfg bar_for_foo --cfg valbar_for_et_foo
|
||||
//[b01011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_et_foo
|
||||
//[b01100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_et_foo
|
||||
//[b01101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_et_foo
|
||||
//[b01110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo
|
||||
//[b01111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo
|
||||
//[b10000]compile-flags: --cfg valbar_for_etmut_foo
|
||||
//[b10001]compile-flags: --cfg inherent_mut --cfg valbar_for_etmut_foo
|
||||
//[b10010]compile-flags: --cfg bar_for_foo --cfg valbar_for_etmut_foo
|
||||
//[b10011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_etmut_foo
|
||||
//[b10100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
|
||||
//[b10101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
|
||||
//[b10110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
|
||||
//[b10111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_etmut_foo
|
||||
//[b11000]compile-flags: --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
//[b11001]compile-flags: --cfg inherent_mut --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
//[b11010]compile-flags: --cfg bar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
//[b11011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
//[b11100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
//[b11101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
//[b11110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
//[b11111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo
|
||||
|
||||
struct Foo {}
|
||||
|
||||
type S = &'static str;
|
||||
|
||||
trait Bar {
|
||||
fn bar(&self, _: &str) -> S;
|
||||
}
|
||||
|
||||
trait MutBar {
|
||||
fn bar(&mut self, _: &str) -> S;
|
||||
}
|
||||
|
||||
trait ValBar {
|
||||
fn bar(self, _: &str) -> S;
|
||||
}
|
||||
|
||||
#[cfg(inherent_mut)]
|
||||
impl Foo {
|
||||
fn bar(&mut self, _: &str) -> S {
|
||||
"In struct impl!"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(bar_for_foo)]
|
||||
impl Bar for Foo {
|
||||
fn bar(&self, _: &str) -> S {
|
||||
"In trait &self impl!"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(mutbar_for_foo)]
|
||||
impl MutBar for Foo {
|
||||
fn bar(&mut self, _: &str) -> S {
|
||||
"In trait &mut self impl!"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(valbar_for_et_foo)]
|
||||
impl ValBar for &Foo {
|
||||
fn bar(self, _: &str) -> S {
|
||||
"In trait self impl for &Foo!"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(valbar_for_etmut_foo)]
|
||||
impl ValBar for &mut Foo {
|
||||
fn bar(self, _: &str) -> S {
|
||||
"In trait self impl for &mut Foo!"
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#![allow(unused_mut)] // some of the impls above will want it.
|
||||
|
||||
#![allow(unreachable_patterns)] // the cfg-coding pattern below generates unreachable patterns.
|
||||
|
||||
{
|
||||
macro_rules! all_variants_on_value {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
#[cfg(bar_for_foo)]
|
||||
x => assert_eq!(x, "In trait &self impl!"),
|
||||
|
||||
#[cfg(valbar_for_et_foo)]
|
||||
x => assert_eq!(x, "In trait self impl for &Foo!"),
|
||||
|
||||
#[cfg(inherent_mut)]
|
||||
x => assert_eq!(x, "In struct impl!"),
|
||||
|
||||
#[cfg(mutbar_for_foo)]
|
||||
x => assert_eq!(x, "In trait &mut self impl!"),
|
||||
|
||||
#[cfg(valbar_for_etmut_foo)]
|
||||
x => assert_eq!(x, "In trait self impl for &mut Foo!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut f = Foo {};
|
||||
all_variants_on_value!(f.bar("f.bar"));
|
||||
|
||||
let f_mr = &mut Foo {};
|
||||
all_variants_on_value!((*f_mr).bar("(*f_mr).bar"));
|
||||
}
|
||||
|
||||
// This is sort of interesting: `&mut Foo` ends up with a significantly
|
||||
// different resolution order than what was devised above. Presumably this
|
||||
// is because we can get to a `&self` method by first a deref of the given
|
||||
// `&mut Foo` and then an autoref, and that is a longer path than a mere
|
||||
// auto-ref of a `Foo`.
|
||||
|
||||
{
|
||||
let f_mr = &mut Foo {};
|
||||
|
||||
match f_mr.bar("f_mr.bar") {
|
||||
#[cfg(inherent_mut)]
|
||||
x => assert_eq!(x, "In struct impl!"),
|
||||
|
||||
#[cfg(valbar_for_etmut_foo)]
|
||||
x => assert_eq!(x, "In trait self impl for &mut Foo!"),
|
||||
|
||||
#[cfg(mutbar_for_foo)]
|
||||
x => assert_eq!(x, "In trait &mut self impl!"),
|
||||
|
||||
#[cfg(valbar_for_et_foo)]
|
||||
x => assert_eq!(x, "In trait self impl for &Foo!"),
|
||||
|
||||
#[cfg(bar_for_foo)]
|
||||
x => assert_eq!(x, "In trait &self impl!"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Note that this isn't actually testing a resolution order; if both of these are
|
||||
// enabled, it yields an ambiguous method resolution error. The test tries to embed
|
||||
// that fact by testing *both* orders (and so the only way that can be right is if
|
||||
// they are not actually compatible).
|
||||
#[cfg(any(bar_for_foo, valbar_for_et_foo))]
|
||||
{
|
||||
let f_r = &Foo {};
|
||||
|
||||
match f_r.bar("f_r.bar") {
|
||||
#[cfg(bar_for_foo)]
|
||||
x => assert_eq!(x, "In trait &self impl!"),
|
||||
|
||||
#[cfg(valbar_for_et_foo)]
|
||||
x => assert_eq!(x, "In trait self impl for &Foo!"),
|
||||
}
|
||||
|
||||
match f_r.bar("f_r.bar") {
|
||||
#[cfg(valbar_for_et_foo)]
|
||||
x => assert_eq!(x, "In trait self impl for &Foo!"),
|
||||
|
||||
#[cfg(bar_for_foo)]
|
||||
x => assert_eq!(x, "In trait &self impl!"),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user