Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
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.)
- Loading branch information
Showing
1 changed file
with
190 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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!"), | ||
} | ||
} | ||
|
||
} |