// edition:2018
// aux-build:edition-lint-infer-outlives-macro.rs
// run-rustfix

#![deny(explicit_outlives_requirements)]
#![allow(dead_code)]

#[macro_use]
extern crate edition_lint_infer_outlives_macro;

// Test that the lint does not fire if the predicate is from the local crate,
// but all the bounds are from an external macro.
macro_rules! make_foo {
    ($a:tt) => {
        struct Foo<$a, 'b: $a> {
            foo: &$a &'b (),
        }

        struct FooWhere<$a, 'b> where 'b: $a {
            foo: &$a &'b (),
        }
    }
}

gimme_a! {make_foo!}

struct Bar<'a, 'b> {
    //~^ ERROR: outlives requirements can be inferred
    bar: &'a &'b (),
}

struct BarWhere<'a, 'b> {
    //~^ ERROR: outlives requirements can be inferred
    bar: &'a &'b (),
}

// Test that the lint *does* fire if the predicate is contained in a local macro.
mod everything_inside {
    macro_rules! m {
        ('b: 'a) => {
            struct Foo<'a, 'b>(&'a &'b ());
            //~^ ERROR: outlives requirements can be inferred
            struct Bar<'a, 'b>(&'a &'b ()) ;
            //~^ ERROR: outlives requirements can be inferred
            struct Baz<'a, 'b>(&'a &'b ()) where (): Sized, ;
            //~^ ERROR: outlives requirements can be inferred
        };
    }
    m!('b: 'a);
}

mod inner_lifetime_outside_colon_inside {
    macro_rules! m {
        ($b:lifetime: 'a) => {
            struct Foo<'a, $b>(&'a &$b ());
            //~^ ERROR: outlives requirements can be inferred
            struct Bar<'a, $b>(&'a &$b ()) ;
            //~^ ERROR: outlives requirements can be inferred
            struct Baz<'a, $b>(&'a &$b ()) where (): Sized, ;
            //~^ ERROR: outlives requirements can be inferred
        }
    }
    m!('b: 'a);
}

mod outer_lifetime_outside_colon_inside {
    macro_rules! m {
        ('b: $a:lifetime) => {
            struct Foo<$a, 'b: $a>(&$a &'b ());
            struct Bar<$a, 'b>(&$a &'b ()) where 'b: $a;
            struct Baz<$a, 'b>(&$a &'b ()) where (): Sized, 'b: $a;
        }
    }
    m!('b: 'a);
}

mod both_lifetimes_outside_colon_inside {
    macro_rules! m {
        ($b:lifetime: $a:lifetime) => {
            struct Foo<$a, $b: $a>(&$a &$b ());
            struct Bar<$a, $b>(&$a &$b ()) where $b: $a;
            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b: $a;
        }
    }
    m!('b: 'a);
}

mod everything_outside {
    macro_rules! m {
        ($b:lifetime $colon:tt $a:lifetime) => {
            struct Foo<$a, $b $colon $a>(&$a &$b ());
            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
        }
    }
    m!('b: 'a);
}

mod everything_outside_with_tt_inner {
    macro_rules! m {
        ($b:tt $colon:tt $a:lifetime) => {
            struct Foo<$a, $b $colon $a>(&$a &$b ());
            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
        }
    }
    m!('b: 'a);
}

// FIXME: These should be consistent.
mod everything_outside_with_tt_outer {
    macro_rules! m {
        ($b:lifetime $colon:tt $a:tt) => {
            struct Foo<$a, $b >(&$a &$b ());
            //~^ ERROR: outlives requirements can be inferred
            struct Bar<$a, $b>(&$a &$b ()) where $b $colon $a;
            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, $b $colon $a;
        }
    }
    m!('b: 'a);
}

mod everything_outside_with_tt_both {
    macro_rules! m {
        ($b:tt $colon:tt $a:tt) => {
            struct Foo<$a, $b >(&$a &$b ());
            //~^ ERROR: outlives requirements can be inferred
            struct Bar<$a, $b>(&$a &$b ()) where ;
            //~^ ERROR: outlives requirements can be inferred
            struct Baz<$a, $b>(&$a &$b ()) where (): Sized, ;
            //~^ ERROR: outlives requirements can be inferred
        }
    }
    m!('b: 'a);
}

fn main() {}