From 1de894f0c1882aed5b6fba6b665de7664626bd59 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 20 Sep 2024 22:59:03 -0400 Subject: [PATCH] More tests and tweak comments --- .../src/collect/resolve_bound_vars.rs | 19 +++++-- .../bad-inputs-and-output.rs | 18 +++++++ .../bad-inputs-and-output.stderr | 39 +++++++++++++- .../higher-ranked-bound-works.rs | 52 +++++++++++++++++++ .../higher-ranked-bound-works.stderr | 11 ++++ .../namespace-conflict.rs | 42 +++++++++++++++ .../namespace-conflict.stderr | 11 ++++ .../return-type-notation/non-rpitit.rs | 7 ++- .../return-type-notation/non-rpitit.stderr | 19 +++++-- .../return-type-notation/not-a-method.rs | 42 +++++++++++++++ .../return-type-notation/not-a-method.stderr | 49 +++++++++++++++++ 11 files changed, 298 insertions(+), 11 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 71d9703bb0e..d1601446b6f 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1640,9 +1640,9 @@ fn visit_segment_args( // } // ``` // and a bound that looks like: - // `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>` + // `for<'a> T::Trait<'a, x(..): for<'b> Other<'b>>` // this is going to expand to something like: - // `for<'a> for<'r, T> >::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. + // `for<'a> for<'r> >::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { let bound_vars = if let Some(type_def_id) = type_def_id @@ -1853,13 +1853,13 @@ fn uninsert_lifetime_on_error( // For example, given // ``` // trait Foo { - // async fn x<'r, T>(); + // async fn x<'r>(); // } // ``` // and a bound that looks like: // `for<'a, 'b> >::x(): Other<'b>` // this is going to expand to something like: - // `for<'a, 'b, 'r, T> >::x::<'r, T>::{opaque#0}: Other<'b>`. + // `for<'a, 'b, 'r> >::x::<'r, T>::{opaque#0}: Other<'b>`. // // We handle this similarly for associated-type-bound style return-type-notation // in `visit_segment_args`. @@ -2000,6 +2000,17 @@ fn try_append_return_type_notation_params( // the new bound vars. We do this because we need to know how many bound vars // are present on the binder explicitly (i.e. not return-type-notation vars) // to do bound var shifting correctly in HIR lowering. + // + // For example, in `where for<'a> >::method(..): Other`, + // the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's + // parent) will include `'a` AND all the early- and late-bound vars of the + // method. But when lowering the RTN type, we just want the list of vars + // we used to resolve the trait ref. We explicitly stored those back onto + // the item segment, since there's no other good place to put them. + // + // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`. + // And this is exercised in: + // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`. let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); let existing_bound_vars_saved = existing_bound_vars.clone(); existing_bound_vars.extend(bound_vars); diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index a8c8a85c5aa..af64901ace0 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -16,4 +16,22 @@ fn bar (): Send>>() {} fn baz>() {} //~^ ERROR return type notation arguments must be elided with `..` +fn foo_path() where T::method(i32): Send {} +//~^ ERROR argument types not allowed with return type notation + +fn bar_path() where T::method() -> (): Send {} +//~^ ERROR return type not allowed with return type notation + +fn baz_path() where T::method(): Send {} +//~^ ERROR return type notation arguments must be elided with `..` + +fn foo_qualified() where ::method(i32): Send {} +//~^ ERROR expected associated type + +fn bar_qualified() where ::method() -> (): Send {} +//~^ ERROR expected associated type + +fn baz_qualified() where ::method(): Send {} +//~^ ERROR expected associated type + fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index 7e1695984f1..68081470087 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,3 +1,21 @@ +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:28:36 + | +LL | fn foo_qualified() where ::method(i32): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:31:36 + | +LL | fn bar_qualified() where ::method() -> (): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:34:36 + | +LL | fn baz_qualified() where ::method(): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^ not a associated type + warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:3:12 | @@ -25,5 +43,24 @@ error: return type notation arguments must be elided with `..` LL | fn baz>() {} | ^^ help: add `..`: `(..)` -error: aborting due to 3 previous errors; 1 warning emitted +error: argument types not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:19:40 + | +LL | fn foo_path() where T::method(i32): Send {} + | ^^^^^ help: remove the input types: `()` +error: return type not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:22:42 + | +LL | fn bar_path() where T::method() -> (): Send {} + | ^^^^^^ help: remove the return type + +error: return type notation arguments must be elided with `..` + --> $DIR/bad-inputs-and-output.rs:25:40 + | +LL | fn baz_path() where T::method(): Send {} + | ^^ help: add `..`: `(..)` + +error: aborting due to 9 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0575`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs new file mode 100644 index 00000000000..d4f21f47c6c --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs @@ -0,0 +1,52 @@ +//@ check-pass + +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait<'a> { + fn late<'b>(&'b self, _: &'a ()) -> impl Sized; + fn early<'b: 'b>(&'b self, _: &'a ()) -> impl Sized; +} + +#[allow(refining_impl_trait_internal)] +impl<'a> Trait<'a> for () { + fn late<'b>(&'b self, _: &'a ()) -> i32 { 1 } + fn early<'b: 'b>(&'b self, _: &'a ()) -> i32 { 1 } +} + +trait Other<'c> {} +impl Other<'_> for i32 {} + +fn test(t: &T) +where + T: for<'a, 'c> Trait<'a, late(..): Other<'c>>, + // which is basically: + // for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>, + T: for<'a, 'c> Trait<'a, early(..): Other<'c>>, + // which is basically: + // for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>, +{ + is_other_impl(t.late(&())); + is_other_impl(t.early(&())); +} + +fn test_path(t: &T) +where +T: for<'a> Trait<'a>, + for<'a, 'c> >::late(..): Other<'c>, + // which is basically: + // for<'a, 'b, 'c> >::method::<'b>: Other<'c> + for<'a, 'c> >::early(..): Other<'c>, + // which is basically: + // for<'a, 'b, 'c> >::method::<'b>: Other<'c> +{ + is_other_impl(t.late(&())); + is_other_impl(t.early(&())); +} + +fn is_other_impl(_: impl for<'c> Other<'c>) {} + +fn main() { + test(&()); + test(&()); +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr new file mode 100644 index 00000000000..c67231c07f7 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/higher-ranked-bound-works.rs:3:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs new file mode 100644 index 00000000000..9bdc2d00233 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs @@ -0,0 +1,42 @@ +//@ check-pass + +#![allow(non_camel_case_types)] +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Foo { + type test; + + fn test() -> impl Bar; +} + +fn call_path() +where + T::test(..): Bar, +{ +} + +fn call_bound>() {} + +trait Bar {} +struct NotBar; +struct YesBar; +impl Bar for YesBar {} + +impl Foo for () { + type test = NotBar; + + // Use refinement here so we can observe `YesBar: Bar`. + #[allow(refining_impl_trait_internal)] + fn test() -> YesBar { + YesBar + } +} + +fn main() { + // If `T::test(..)` resolved to the GAT (erroneously), then this would be + // an error since `<() as Foo>::bar` -- the associated type -- does not + // implement `Bar`, but the return type of the method does. + call_path::<()>(); + call_bound::<()>(); +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr new file mode 100644 index 00000000000..f4ece074b28 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/namespace-conflict.rs:4:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs index d283c6eab37..35d6dd799c7 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs @@ -5,7 +5,10 @@ trait Trait { fn method() {} } -fn test>() {} -//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` +fn bound>() {} +//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` + +fn path() where T: Trait, T::method(..): Send {} +//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr index 79ced3c96ed..e308c927bf0 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr @@ -8,15 +8,26 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: return type notation used on function that is not `async` and does not return `impl Trait` - --> $DIR/non-rpitit.rs:8:18 + --> $DIR/non-rpitit.rs:8:19 | LL | fn method() {} | ----------- this function must be `async` or return `impl Trait` ... -LL | fn test>() {} - | ^^^^^^^^^^^^^^^^ +LL | fn bound>() {} + | ^^^^^^^^^^^^^^^^ | = note: function returns `()`, which is not compatible with associated type return bounds -error: aborting due to 1 previous error; 1 warning emitted +error: return type notation used on function that is not `async` and does not return `impl Trait` + --> $DIR/non-rpitit.rs:11:30 + | +LL | fn method() {} + | ----------- this function must be `async` or return `impl Trait` +... +LL | fn path() where T: Trait, T::method(..): Send {} + | ^^^^^^^^^^^^^ + | + = note: function returns `()`, which is not compatible with associated type return bounds + +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs new file mode 100644 index 00000000000..d94ec6b74d9 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs @@ -0,0 +1,42 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +fn function() {} + +fn not_a_method() +where + function(..): Send, + //~^ ERROR expected function, found function `function` + //~| ERROR return type notation not allowed in this position yet +{ +} + +fn not_a_method_and_typoed() +where + function(): Send, + //~^ ERROR expected type, found function `function` +{ +} + +trait Tr { + fn method(); +} + +// Forgot the `T::` +fn maybe_method_overlaps() +where + method(..): Send, + //~^ ERROR cannot find function `method` in this scope + //~| ERROR return type notation not allowed in this position yet +{ +} + +// Forgot the `T::`, AND typoed `(..)` to `()` +fn maybe_method_overlaps_and_typoed() +where + method(): Send, + //~^ ERROR cannot find type `method` in this scope +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr new file mode 100644 index 00000000000..8add2d46296 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr @@ -0,0 +1,49 @@ +error[E0575]: expected function, found function `function` + --> $DIR/not-a-method.rs:8:5 + | +LL | function(..): Send, + | ^^^^^^^^^^^^ not a function + +error[E0573]: expected type, found function `function` + --> $DIR/not-a-method.rs:16:5 + | +LL | function(): Send, + | ^^^^^^^^^^ not a type + +error[E0576]: cannot find function `method` in this scope + --> $DIR/not-a-method.rs:28:5 + | +LL | method(..): Send, + | ^^^^^^ not found in this scope + +error[E0412]: cannot find type `method` in this scope + --> $DIR/not-a-method.rs:37:5 + | +LL | method(): Send, + | ^^^^^^ not found in this scope + +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/not-a-method.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation not allowed in this position yet + --> $DIR/not-a-method.rs:8:5 + | +LL | function(..): Send, + | ^^^^^^^^^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/not-a-method.rs:28:5 + | +LL | method(..): Send, + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0412, E0573, E0575, E0576. +For more information about an error, try `rustc --explain E0412`.