From 3c659f325a41a3a02ddd7d563c5fd32e7e8812e0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 10 Jan 2024 16:50:45 +0100 Subject: [PATCH 1/3] move leak check out of candidate evaluation this prevents higher ranked goals from guiding selection --- .../src/traits/select/mod.rs | 39 ++++-- .../trait-bounds/fn-ptr.classic.stderr | 19 --- tests/ui/higher-ranked/trait-bounds/fn-ptr.rs | 3 +- .../trait-bounds/future.classic.stderr | 6 - tests/ui/higher-ranked/trait-bounds/future.rs | 10 +- ...check-does-not-guide-selection.next.stderr | 22 ++++ ...-check-does-not-guide-selection.old.stderr | 22 ++++ .../hr-leak-check-does-not-guide-selection.rs | 22 ++++ ...igher-ranker-supertraits-transitive.stderr | 22 ++-- .../hrtb-higher-ranker-supertraits.rs | 32 ++--- .../hrtb-higher-ranker-supertraits.stderr | 78 +++++++----- .../{issue-30786.rs => issue-30786-1.rs} | 22 +--- .../trait-bounds/issue-30786-1.stderr | 50 ++++++++ .../trait-bounds/issue-30786-2.rs | 116 ++++++++++++++++++ .../trait-bounds/issue-30786-2.stderr | 21 ++++ .../trait-bounds/issue-30786.stderr | 39 ------ tests/ui/implied-bounds/issue-100690.rs | 11 +- tests/ui/implied-bounds/issue-100690.stderr | 54 +++++--- 18 files changed, 402 insertions(+), 186 deletions(-) delete mode 100644 tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr delete mode 100644 tests/ui/higher-ranked/trait-bounds/future.classic.stderr create mode 100644 tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.next.stderr create mode 100644 tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.old.stderr create mode 100644 tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.rs rename tests/ui/higher-ranked/trait-bounds/{issue-30786.rs => issue-30786-1.rs} (86%) create mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr create mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs create mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr delete mode 100644 tests/ui/higher-ranked/trait-bounds/issue-30786.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6a6adcbb680ea..90a23cc9a2fc0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -580,7 +580,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result { debug_assert!(!self.infcx.next_trait_solver()); - self.evaluation_probe(|this| { + self.evaluation_probe(|this, _outer_universe| { let goal = this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); let mut result = this.evaluate_predicate_recursively( @@ -596,13 +596,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Computes the evaluation result of `op`, discarding any constraints. + /// + /// This also runs for leak check to allow higher ranked region errors to impact + /// selection. By default it checks for leaks from all universes created inside of + /// `op`, but this can be overwritten if necessary. fn evaluation_probe( &mut self, - op: impl FnOnce(&mut Self) -> Result, + op: impl FnOnce(&mut Self, &mut ty::UniverseIndex) -> Result, ) -> Result { self.infcx.probe(|snapshot| -> Result { - let outer_universe = self.infcx.universe(); - let result = op(self)?; + let mut outer_universe = self.infcx.universe(); + let result = op(self, &mut outer_universe)?; match self.infcx.leak_check(outer_universe, Some(snapshot)) { Ok(()) => {} @@ -1265,9 +1270,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, ) -> Result { - let mut result = self.evaluation_probe(|this| { - let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { + let mut result = self.evaluation_probe(|this, outer_universe| { + // We eagerly instantiate higher ranked goals to prevent universe errors + // from impacting candidate selection. This matches the behavior of the new + // solver. This slightly weakens type inference. + // + // In case there are no unresolved type or const variables this + // should still not be necessary to select a unique impl as any overlap + // relying on a universe error from higher ranked goals should have resulted + // in an overlap error in coherence. + let p = self.infcx.instantiate_binder_with_placeholders(stack.obligation.predicate); + let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p)); + *outer_universe = self.infcx.universe(); + match this.confirm_candidate(&obligation, candidate.clone()) { Ok(selection) => { debug!(?selection); this.evaluate_predicates_recursively( @@ -1704,8 +1719,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result { - self.evaluation_probe(|this| { - match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + self.evaluation_probe(|this, outer_universe| { + // Eagerly instantiate higher ranked goals. + // + // See the comment in `evaluate_candidate` to see why. + let p = self.infcx.instantiate_binder_with_placeholders(stack.obligation.predicate); + let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p)); + *outer_universe = self.infcx.universe(); + match this.match_where_clause_trait_ref(&obligation, where_clause_trait_ref) { Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations), Err(()) => Ok(EvaluatedToErr), } diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr b/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr deleted file mode 100644 index b322ea41c436d..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.classic.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: expected a `Fn(&'w ())` closure, found `fn(&'w ())` - --> $DIR/fn-ptr.rs:12:5 - | -LL | ice(); - | ^^^^^ expected an `Fn(&'w ())` closure, found `fn(&'w ())` - | - = help: the trait `for<'w> Fn<(&'w (),)>` is not implemented for `fn(&'w ())` -note: required by a bound in `ice` - --> $DIR/fn-ptr.rs:7:25 - | -LL | fn ice() - | --- required by a bound in this function -LL | where -LL | for<'w> fn(&'w ()): Fn(&'w ()), - | ^^^^^^^^^^ required by this bound in `ice` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs index 41f24dde01adc..d1d1818534ed5 100644 --- a/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs +++ b/tests/ui/higher-ranked/trait-bounds/fn-ptr.rs @@ -1,6 +1,6 @@ // revisions: classic next //[next] compile-flags: -Znext-solver -//[next] check-pass +// check-pass fn ice() where @@ -10,5 +10,4 @@ where fn main() { ice(); - //[classic]~^ ERROR expected a `Fn(&'w ())` closure, found `fn(&'w ())` } diff --git a/tests/ui/higher-ranked/trait-bounds/future.classic.stderr b/tests/ui/higher-ranked/trait-bounds/future.classic.stderr deleted file mode 100644 index ef31b7266c7ef..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/future.classic.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: the compiler unexpectedly panicked. this is a bug. - -query stack during panic: -#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body@$DIR/future.rs:32:35: 34:2}: core::future::future::Future` -#1 [codegen_select_candidate] computing candidate for `` -end of query stack diff --git a/tests/ui/higher-ranked/trait-bounds/future.rs b/tests/ui/higher-ranked/trait-bounds/future.rs index baeb56e5d78cd..0e32674f46d5b 100644 --- a/tests/ui/higher-ranked/trait-bounds/future.rs +++ b/tests/ui/higher-ranked/trait-bounds/future.rs @@ -1,15 +1,7 @@ -// ignore-tidy-linelength // edition:2021 // revisions: classic next //[next] compile-flags: -Znext-solver -//[next] check-pass -//[classic] known-bug: #112347 -//[classic] build-fail -//[classic] failure-status: 101 -//[classic] normalize-stderr-test "note: .*\n\n" -> "" -//[classic] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> "" -//[classic] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//[classic] rustc-env:RUST_BACKTRACE=0 +// check-pass #![feature(unboxed_closures)] diff --git a/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.next.stderr b/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.next.stderr new file mode 100644 index 0000000000000..81b83da02c0bd --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.next.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed + --> $DIR/hr-leak-check-does-not-guide-selection.rs:20:5 + | +LL | impl_trait::>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impl_trait` + | +note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found + --> $DIR/hr-leak-check-does-not-guide-selection.rs:14:1 + | +LL | impl<'a> Leak<'a> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impl_trait` + --> $DIR/hr-leak-check-does-not-guide-selection.rs:17:18 + | +LL | fn impl_trait Leak<'a>>() {} + | ^^^^^^^^^^^^^^^^ required by this bound in `impl_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.old.stderr b/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.old.stderr new file mode 100644 index 0000000000000..81b83da02c0bd --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.old.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed + --> $DIR/hr-leak-check-does-not-guide-selection.rs:20:5 + | +LL | impl_trait::>(); + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impl_trait` + | +note: multiple `impl`s satisfying `for<'a> Box<_>: Leak<'a>` found + --> $DIR/hr-leak-check-does-not-guide-selection.rs:14:1 + | +LL | impl<'a> Leak<'a> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Leak<'static> for Box {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `impl_trait` + --> $DIR/hr-leak-check-does-not-guide-selection.rs:17:18 + | +LL | fn impl_trait Leak<'a>>() {} + | ^^^^^^^^^^^^^^^^ required by this bound in `impl_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.rs b/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.rs new file mode 100644 index 0000000000000..631536007c119 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/hr-leak-check-does-not-guide-selection.rs @@ -0,0 +1,22 @@ +// When proving the higher ranked goal `for<'a> Box<_>: Leak<'a>` the +// impl for `Box` would result in a higher ranked region error. +// +// However, we instantiate higher ranked goals outside of candidate +// selection, so we end up with ambiguity. The old solver previously +// used the leak check to guide selection here. +// +// See trait-system-refactor-initiative#34 for more details here. + +// revisions: next old +//[next] compile-flags: -Znext-solver + +trait Leak<'a> {} +impl<'a> Leak<'a> for Box {} +impl Leak<'static> for Box {} + +fn impl_trait Leak<'a>>() {} + +fn main() { + impl_trait::>(); + //~^ ERROR type annotations needed +} diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr index e10da26665ebb..147a85135b100 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,23 +1,17 @@ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26 +error[E0308]: mismatched types + --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | LL | want_bar_for_any_ccx(b); - | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | -note: required by a bound in `want_bar_for_any_ccx` + = note: expected trait `for<'ccx> Bar<'ccx>` + found trait `Bar<'static>` +note: the lifetime requirement is introduced here --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15 | -LL | fn want_bar_for_any_ccx(b: &B) - | -------------------- required by a bound in this function LL | where B : for<'ccx> Bar<'ccx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound - | -LL | where B : Qux + for<'ccx> Bar<'ccx> - | +++++++++++++++++++++ + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs index 48ebe5017aa62..03644970cf774 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.rs @@ -1,43 +1,37 @@ // Test a trait (`Bar`) with a higher-ranked supertrait. +#![allow(unconditional_recursion)] -trait Foo<'tcx> -{ +trait Foo<'tcx> { fn foo(&'tcx self) -> &'tcx isize; } -trait Bar<'ccx> - : for<'tcx> Foo<'tcx> -{ +trait Bar<'ccx>: for<'tcx> Foo<'tcx> { fn bar(&'ccx self) -> &'ccx isize; } -fn want_foo_for_some_tcx<'x,F>(f: &'x F) - where F : Foo<'x> -{ +fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) { want_foo_for_some_tcx(f); - want_foo_for_any_tcx(f); //~ ERROR not satisfied + want_foo_for_any_tcx(f); + //~^ ERROR lifetime may not live long enough + //~| ERROR mismatched types } -fn want_foo_for_any_tcx(f: &F) - where F : for<'tcx> Foo<'tcx> -{ +fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { want_foo_for_some_tcx(f); want_foo_for_any_tcx(f); } -fn want_bar_for_some_ccx<'x,B>(b: &B) - where B : Bar<'x> -{ +fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) { want_foo_for_some_tcx(b); want_foo_for_any_tcx(b); want_bar_for_some_ccx(b); - want_bar_for_any_ccx(b); //~ ERROR not satisfied + want_bar_for_any_ccx(b); + //~^ ERROR lifetime may not live long enough + //~| ERROR mismatched types } -fn want_bar_for_any_ccx(b: &B) - where B : for<'ccx> Bar<'ccx> -{ +fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { want_foo_for_some_tcx(b); want_foo_for_any_tcx(b); diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr index 7f96909b6e76e..6f2255f517f1a 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr @@ -1,43 +1,61 @@ -error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26 +error: lifetime may not live long enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5 | +LL | fn want_foo_for_some_tcx<'x, F: Foo<'x>>(f: &'x F) { + | -- lifetime `'x` defined here +LL | want_foo_for_some_tcx(f); LL | want_foo_for_any_tcx(f); - | -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static` | -note: required by a bound in `want_foo_for_any_tcx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:22:15 +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-higher-ranker-supertraits.rs:19:28 | -LL | fn want_foo_for_any_tcx(f: &F) - | -------------------- required by a bound in this function -LL | where F : for<'tcx> Foo<'tcx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx` -help: consider further restricting this bound +LL | fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/hrtb-higher-ranker-supertraits.rs:14:5 + | +LL | want_foo_for_any_tcx(f); + | ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected trait `for<'tcx> Foo<'tcx>` + found trait `Foo<'_>` +note: the lifetime requirement is introduced here + --> $DIR/hrtb-higher-ranker-supertraits.rs:19:28 | -LL | where F : Foo<'x> + for<'tcx> Foo<'tcx> - | +++++++++++++++++++++ +LL | fn want_foo_for_any_tcx Foo<'tcx>>(f: &F) { + | ^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied - --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26 +error: lifetime may not live long enough + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5 | +LL | fn want_bar_for_some_ccx<'x, B: Bar<'x>>(b: &B) { + | -- lifetime `'x` defined here +... LL | want_bar_for_any_ccx(b); - | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ requires that `'x` must outlive `'static` | -note: required by a bound in `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:39:15 +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/hrtb-higher-ranker-supertraits.rs:34:28 + | +LL | fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { + | ^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/hrtb-higher-ranker-supertraits.rs:29:5 + | +LL | want_bar_for_any_ccx(b); + | ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | -LL | fn want_bar_for_any_ccx(b: &B) - | -------------------- required by a bound in this function -LL | where B : for<'ccx> Bar<'ccx> - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound + = note: expected trait `for<'ccx> Bar<'ccx>` + found trait `Bar<'_>` +note: the lifetime requirement is introduced here + --> $DIR/hrtb-higher-ranker-supertraits.rs:34:28 | -LL | where B : Bar<'x> + for<'ccx> Bar<'ccx> - | +++++++++++++++++++++ +LL | fn want_bar_for_any_ccx Bar<'ccx>>(b: &B) { + | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs similarity index 86% rename from tests/ui/higher-ranked/trait-bounds/issue-30786.rs rename to tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs index 4a6399c8f6246..349fae23a1ea4 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs @@ -97,10 +97,6 @@ where impl StreamExt for T where for<'a> &'a mut T: Stream {} -fn identity(x: &T) -> &T { - x -} - fn variant1() { let source = Repeat(10); @@ -117,20 +113,12 @@ fn variant1() { // we deduce it somehow from a reuqirement that `Map: Stream` I // guess. let map = source.mapx(|x: &_| x); + //~^ ERROR implementation of `FnOnce` is not general enough let filter = map.filterx(|x: &_| true); - //~^ ERROR the method -} - -fn variant2() { - let source = Repeat(10); - - // Here, we use a function, which is not subject to the vagaries - // of closure signature inference. In this case, we get the error - // on `countx` as, I think, the test originally expected. - let map = source.mapx(identity); - let filter = map.filterx(|x: &_| true); - let count = filter.countx(); - //~^ ERROR the method + //~^ ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough + //~| ERROR implementation of `FnOnce` is not general enough } fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr new file mode 100644 index 0000000000000..3ad92de423f61 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr @@ -0,0 +1,50 @@ +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-30786-1.rs:115:15 + | +LL | let map = source.mapx(|x: &_| x); + | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-30786-1.rs:117:18 + | +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-30786-1.rs:117:18 + | +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-30786-1.rs:117:18 + | +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: implementation of `FnOnce` is not general enough + --> $DIR/issue-30786-1.rs:117:18 + | +LL | let filter = map.filterx(|x: &_| true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | + = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... + = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs new file mode 100644 index 0000000000000..cc2cdcef1ca33 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.rs @@ -0,0 +1,116 @@ +// normalize-stderr-test: "long-type-\d+" -> "long-type-hash" + +// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream Option; +} + +// Example stream +pub struct Repeat(u64); + +impl<'a> Stream for &'a mut Repeat { + type Item = &'a u64; + fn next(self) -> Option { + Some(&self.0) + } +} + +pub struct Map { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Map +where + &'a mut A: Stream, + F: FnMut(<&'a mut A as Stream>::Item) -> T, +{ + type Item = T; + fn next(self) -> Option { + match self.stream.next() { + Some(item) => Some((self.func)(item)), + None => None, + } + } +} + +pub struct Filter { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Filter +where + for<'b> &'b mut A: Stream, // <---- BAD + F: FnMut(&T) -> bool, +{ + type Item = <&'a mut A as Stream>::Item; + fn next(self) -> Option { + while let Some(item) = self.stream.next() { + if (self.func)(&item) { + return Some(item); + } + } + None + } +} + +pub trait StreamExt +where + for<'b> &'b mut Self: Stream, +{ + fn mapx(self, func: F) -> Map + where + Self: Sized, + for<'a> &'a mut Map: Stream, + { + Map { func: func, stream: self } + } + + fn filterx(self, func: F) -> Filter + where + Self: Sized, + for<'a> &'a mut Filter: Stream, + { + Filter { func: func, stream: self } + } + + fn countx(mut self) -> usize + where + Self: Sized, + { + let mut count = 0; + while let Some(_) = self.next() { + count += 1; + } + count + } +} + +impl StreamExt for T where for<'a> &'a mut T: Stream {} + +fn identity(x: &T) -> &T { + x +} + +fn variant2() { + let source = Repeat(10); + + // Here, we use a function, which is not subject to the vagaries + // of closure signature inference. In this case, we get the error + // on `countx` as, I think, the test originally expected. + let map = source.mapx(identity); + let filter = map.filterx(|x: &_| true); + let count = filter.countx(); + //~^ ERROR the method +} + +fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr new file mode 100644 index 0000000000000..f6fa242f28ef0 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-2.stderr @@ -0,0 +1,21 @@ +error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786-2.rs:111:30}>`, but its trait bounds were not satisfied + --> $DIR/issue-30786-2.rs:112:24 + | +LL | pub struct Filter { + | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` +... +LL | let count = filter.countx(); + | ^^^^^^ method cannot be called due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` + `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` + `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786-2.rs:111:30: 111:37}>: Stream` + --> $DIR/issue-30786-2.rs:98:50 + | +LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} + | --------- - ^^^^^^ unsatisfied trait bound introduced here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr deleted file mode 100644 index 73870703cfbac..0000000000000 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:120:22 - | -LL | pub struct Map { - | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` -... -LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&'a mut &Map: Stream` - `&'a mut &mut Map: Stream` - `&'a mut Map: Stream` - --> $DIR/issue-30786.rs:98:50 - | -LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} - | --------- - ^^^^^^ unsatisfied trait bound introduced here - -error[E0599]: the method `countx` exists for struct `Filter &u64 {identity::}>, {closure@issue-30786.rs:131:30}>`, but its trait bounds were not satisfied - --> $DIR/issue-30786.rs:132:24 - | -LL | pub struct Filter { - | ----------------------- method `countx` not found for this struct because it doesn't satisfy `_: StreamExt` -... -LL | let count = filter.countx(); - | ^^^^^^ method cannot be called due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&'a mut &Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - `&'a mut &mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - `&'a mut Filter fn(&'a u64) -> &'a u64 {identity::}>, {closure@$DIR/issue-30786.rs:131:30: 131:37}>: Stream` - --> $DIR/issue-30786.rs:98:50 - | -LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} - | --------- - ^^^^^^ unsatisfied trait bound introduced here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/implied-bounds/issue-100690.rs b/tests/ui/implied-bounds/issue-100690.rs index ea33c9f423b77..f15bd4152e7f7 100644 --- a/tests/ui/implied-bounds/issue-100690.rs +++ b/tests/ui/implied-bounds/issue-100690.rs @@ -4,11 +4,8 @@ use std::io; fn real_dispatch(f: F) -> Result<(), io::Error> -//~^ NOTE required by a bound in this where F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, - //~^ NOTE required by this bound in `real_dispatch` - //~| NOTE required by a bound in `real_dispatch` { todo!() } @@ -35,10 +32,10 @@ impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandl F: FnOnce(&mut UIView<'a, T>) -> Result<(), io::Error> + Send + 'static, { real_dispatch(f) - //~^ ERROR expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` - //~| NOTE expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` - //~| NOTE expected a closure with arguments - //~| NOTE required by a bound introduced by this call + //~^ ERROR lifetime may not live long enough + //~| ERROR mismatched types + //~| ERROR mismatched types + // } } diff --git a/tests/ui/implied-bounds/issue-100690.stderr b/tests/ui/implied-bounds/issue-100690.stderr index df069d875cebc..ae1023b803ba5 100644 --- a/tests/ui/implied-bounds/issue-100690.stderr +++ b/tests/ui/implied-bounds/issue-100690.stderr @@ -1,22 +1,46 @@ -error[E0277]: expected a `FnOnce(&mut UIView<'_, T>)` closure, found `F` - --> $DIR/issue-100690.rs:37:23 +error: lifetime may not live long enough + --> $DIR/issue-100690.rs:34:9 | +LL | impl<'a, T: 'a> Handle<'a, T, UIView<'a, T>, Result<(), io::Error>> for TUIHandle { + | -- lifetime `'a` defined here +... LL | real_dispatch(f) - | ------------- ^ expected an `FnOnce(&mut UIView<'_, T>)` closure, found `F` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` | - = note: expected a closure with arguments `(&mut UIView<'a, _>,)` - found a closure with arguments `(&mut UIView<'_, _>,)` -note: required by a bound in `real_dispatch` - --> $DIR/issue-100690.rs:9:8 +note: due to current limitations in the borrow checker, this implies a `'static` lifetime + --> $DIR/issue-100690.rs:8:8 + | +LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-100690.rs:34:9 + | +LL | real_dispatch(f) + | ^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected trait `for<'a, 'b> FnOnce(&'a mut UIView<'b, T>)` + found trait `for<'a> FnOnce(&'a mut UIView<'_, T>)` +note: the lifetime requirement is introduced here + --> $DIR/issue-100690.rs:8:8 + | +LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-100690.rs:34:9 + | +LL | real_dispatch(f) + | ^^^^^^^^^^^^^^^^ one type is more general than the other + | + = note: expected associated type `,)>>::Output` + found associated type `,)>>::Output` +note: the lifetime requirement is introduced here + --> $DIR/issue-100690.rs:8:34 | -LL | fn real_dispatch(f: F) -> Result<(), io::Error> - | ------------- required by a bound in this function -... LL | F: FnOnce(&mut UIView) -> Result<(), io::Error> + Send + 'static, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `real_dispatch` + | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. From 6d831fd5c4b417aa989900da01c769ba953749c2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 10 Jan 2024 17:44:36 +0100 Subject: [PATCH 2/3] remove the `coherence_leak_check` lint --- .../src/coherence/inherent_impls_overlap.rs | 13 +--- compiler/rustc_infer/src/infer/at.rs | 1 - compiler/rustc_infer/src/infer/mod.rs | 15 ---- .../src/infer/relate/higher_ranked.rs | 12 ++- compiler/rustc_lint/src/lib.rs | 5 ++ compiler/rustc_lint_defs/src/builtin.rs | 41 ---------- .../src/traits/coherence.rs | 38 ++++------ .../rustc_trait_selection/src/traits/mod.rs | 18 ----- .../src/traits/specialize/mod.rs | 2 - .../traits/specialize/specialization_graph.rs | 76 +++++-------------- .../codegen/subtyping-impacts-selection-1.rs | 1 - .../coherence/coherence-fn-implied-bounds.rs | 18 ++--- .../coherence-fn-implied-bounds.stderr | 20 ----- .../coherence-free-vs-bound-region.rs | 12 +-- .../coherence-free-vs-bound-region.stderr | 20 ----- .../coherence-inherited-subtyping.rs | 19 ----- .../coherence-inherited-subtyping.stderr | 14 ---- .../coherence-inherited-universe-error.rs | 19 +++++ tests/ui/coherence/coherence-subtyping.rs | 13 +--- tests/ui/coherence/coherence-subtyping.stderr | 16 ---- tests/ui/coherence/coherence-wasm-bindgen.rs | 13 +--- .../coherence/coherence-wasm-bindgen.stderr | 27 ------- ...constraints-on-unification.explicit.stderr | 19 ----- ...older-region-constraints-on-unification.rs | 6 +- .../occurs-check/associated-type.next.stderr | 4 - .../occurs-check/associated-type.old.stderr | 4 - tests/ui/const-generics/invariant.rs | 2 - tests/ui/const-generics/invariant.stderr | 18 +---- .../higher-ranked/leak-check-in-selection.rs | 1 - .../ui/mir/important-higher-ranked-regions.rs | 2 +- .../issue-118950-root-region.stderr | 4 - 31 files changed, 87 insertions(+), 386 deletions(-) delete mode 100644 tests/ui/coherence/coherence-fn-implied-bounds.stderr delete mode 100644 tests/ui/coherence/coherence-free-vs-bound-region.stderr delete mode 100644 tests/ui/coherence/coherence-inherited-subtyping.rs delete mode 100644 tests/ui/coherence/coherence-inherited-subtyping.stderr create mode 100644 tests/ui/coherence/coherence-inherited-universe-error.rs delete mode 100644 tests/ui/coherence/coherence-subtyping.stderr delete mode 100644 tests/ui/coherence/coherence-wasm-bindgen.stderr delete mode 100644 tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 951440d6a2d0b..c4616b208a2cd 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -7,7 +7,7 @@ use rustc_index::IndexVec; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{ErrorGuaranteed, Symbol}; -use rustc_trait_selection::traits::{self, SkipLeakCheck}; +use rustc_trait_selection::traits; use smallvec::SmallVec; use std::collections::hash_map::Entry; @@ -145,15 +145,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> { impl1_def_id: DefId, impl2_def_id: DefId, ) -> Result<(), ErrorGuaranteed> { - let maybe_overlap = traits::overlapping_impls( - self.tcx, - impl1_def_id, - impl2_def_id, - // We go ahead and just skip the leak check for - // inherent impls without warning. - SkipLeakCheck::Yes, - overlap_mode, - ); + let maybe_overlap = + traits::overlapping_impls(self.tcx, impl1_def_id, impl2_def_id, overlap_mode); if let Some(overlap) = maybe_overlap { self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 0f1af81d9f04c..cdb882593fc33 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -78,7 +78,6 @@ impl<'tcx> InferCtxt<'tcx> { tcx: self.tcx, defining_use_anchor: self.defining_use_anchor, considering_regions: self.considering_regions, - skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), lexical_region_resolutions: self.lexical_region_resolutions.clone(), selection_cache: self.selection_cache.clone(), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 0a39fe007fd22..53ba947e447d3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -258,12 +258,6 @@ pub struct InferCtxt<'tcx> { /// solving is left to borrowck instead. pub considering_regions: bool, - /// If set, this flag causes us to skip the 'leak check' during - /// higher-ranked subtyping operations. This flag is a temporary one used - /// to manage the removal of the leak-check: for the time being, we still run the - /// leak-check, but we issue warnings. - skip_leak_check: bool, - pub inner: RefCell>, /// Once region inference is done, the values for each variable. @@ -611,7 +605,6 @@ pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, defining_use_anchor: DefiningAnchor, considering_regions: bool, - skip_leak_check: bool, /// Whether we are in coherence mode. intercrate: bool, /// Whether we should use the new trait solver in the local inference context, @@ -629,7 +622,6 @@ impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { tcx: self, defining_use_anchor: DefiningAnchor::Error, considering_regions: true, - skip_leak_check: false, intercrate: false, next_trait_solver: self.next_trait_solver_globally(), } @@ -663,11 +655,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } - pub fn skip_leak_check(mut self, skip_leak_check: bool) -> Self { - self.skip_leak_check = skip_leak_check; - self - } - /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -693,7 +680,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { tcx, defining_use_anchor, considering_regions, - skip_leak_check, intercrate, next_trait_solver, } = *self; @@ -701,7 +687,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { tcx, defining_use_anchor, considering_regions, - skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), selection_cache: Default::default(), diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 440df8c8936f9..3886ea985fd69 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -116,13 +116,11 @@ impl<'tcx> InferCtxt<'tcx> { outer_universe: ty::UniverseIndex, only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>, ) -> RelateResult<'tcx, ()> { - // If the user gave `-Zno-leak-check`, or we have been - // configured to skip the leak check, then skip the leak check - // completely. The leak check is deprecated. Any legitimate - // subtyping errors that it would have caught will now be - // caught later on, during region checking. However, we - // continue to use it for a transition period. - if self.tcx.sess.opts.unstable_opts.no_leak_check || self.skip_leak_check { + // If the user gave `-Zno-leak-check`, then skip the leak check + // completely. While we considered to remove the leak check at + // some point, we are now confident that it will remain in some + // form or another. + if self.tcx.sess.opts.unstable_opts.no_leak_check { return Ok(()); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 1d9ce10bcaf38..f50b37508a437 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -416,6 +416,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see issue #48950 \ for more information", ); + store.register_removed( + "coherence_leak_check", + "no longer a warning, see issue #119820 \ + for more information", + ); store.register_removed( "resolve_trait_on_defaulted_unit", "converted into hard error, see issue #48950 \ diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index e6d837ecd92bd..3ac86a657c048 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -25,7 +25,6 @@ declare_lint_pass! { BREAK_WITH_LABEL_AND_LOOP, BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, CENUM_IMPL_DROP_CAST, - COHERENCE_LEAK_CHECK, CONFLICTING_REPR_HINTS, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, @@ -1467,46 +1466,6 @@ declare_lint! { }; } -declare_lint! { - /// The `coherence_leak_check` lint detects conflicting implementations of - /// a trait that are only distinguished by the old leak-check code. - /// - /// ### Example - /// - /// ```rust - /// trait SomeTrait { } - /// impl SomeTrait for for<'a> fn(&'a u8) { } - /// impl<'a> SomeTrait for fn(&'a u8) { } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// In the past, the compiler would accept trait implementations for - /// identical functions that differed only in where the lifetime binder - /// appeared. Due to a change in the borrow checker implementation to fix - /// several bugs, this is no longer allowed. However, since this affects - /// existing code, this is a [future-incompatible] lint to transition this - /// to a hard error in the future. - /// - /// Code relying on this pattern should introduce "[newtypes]", - /// like `struct Foo(for<'a> fn(&'a u8))`. - /// - /// See [issue #56105] for more details. - /// - /// [issue #56105]: /~https://github.com/rust-lang/rust/issues/56105 - /// [newtypes]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub COHERENCE_LEAK_CHECK, - Warn, - "distinct impls distinguished only by the leak-check code", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #56105 ", - }; -} - declare_lint! { /// The `deprecated` lint detects use of deprecated items. /// diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index c49185a52c7ef..9dc92ba401939 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -14,7 +14,6 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::structural_normalize::StructurallyNormalizeExt; use crate::traits::NormalizeExt; -use crate::traits::SkipLeakCheck; use crate::traits::{ Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations, SelectionContext, @@ -85,12 +84,11 @@ impl TrackAmbiguityCauses { /// If there are types that satisfy both impls, returns `Some` /// with a suitably-freshened `ImplHeader` with those types /// substituted. Otherwise, returns `None`. -#[instrument(skip(tcx, skip_leak_check), level = "debug")] +#[instrument(skip(tcx), level = "debug")] pub fn overlapping_impls( tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId, - skip_leak_check: SkipLeakCheck, overlap_mode: OverlapMode, ) -> Option> { // Before doing expensive operations like entering an inference context, do @@ -115,27 +113,14 @@ pub fn overlapping_impls( return None; } - let _overlap_with_bad_diagnostics = overlap( - tcx, - TrackAmbiguityCauses::No, - skip_leak_check, - impl1_def_id, - impl2_def_id, - overlap_mode, - )?; + let _overlap_with_bad_diagnostics = + overlap(tcx, TrackAmbiguityCauses::No, impl1_def_id, impl2_def_id, overlap_mode)?; // In the case where we detect an error, run the check again, but // this time tracking intercrate ambiguity causes for better // diagnostics. (These take time and can lead to false errors.) - let overlap = overlap( - tcx, - TrackAmbiguityCauses::Yes, - skip_leak_check, - impl1_def_id, - impl2_def_id, - overlap_mode, - ) - .unwrap(); + let overlap = + overlap(tcx, TrackAmbiguityCauses::Yes, impl1_def_id, impl2_def_id, overlap_mode).unwrap(); Some(overlap) } @@ -177,7 +162,6 @@ fn fresh_impl_header_normalized<'tcx>( fn overlap<'tcx>( tcx: TyCtxt<'tcx>, track_ambiguity_causes: TrackAmbiguityCauses, - skip_leak_check: SkipLeakCheck, impl1_def_id: DefId, impl2_def_id: DefId, overlap_mode: OverlapMode, @@ -193,7 +177,6 @@ fn overlap<'tcx>( let infcx = tcx .infer_ctxt() .with_opaque_type_inference(DefiningAnchor::Bubble) - .skip_leak_check(skip_leak_check.is_yes()) .intercrate(true) .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) .build(); @@ -231,8 +214,15 @@ fn overlap<'tcx>( } } - // We toggle the `leak_check` by using `skip_leak_check` when constructing the - // inference context, so this may be a noop. + // Detect any region errors caused by equating these two impls. + // + // Only higher ranked region errors are possible here, given that we + // replaced all parameter regions with existentials. + // + // Unlike a full region check, which sometimes incompletely handles + // `TypeOutlives` constraints, the leak check is a complete. While the + // leak check does not detect all region errors, it never + // fails in cases which would later pass full region checking. if infcx.leak_check(ty::UniverseIndex::ROOT, None).is_err() { debug!("overlap: leak check failed"); return None; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a7f6021d57a96..00c2123c057d2 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -71,24 +71,6 @@ pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upca pub use rustc_infer::traits::*; -/// Whether to skip the leak check, as part of a future compatibility warning step. -/// -/// The "default" for skip-leak-check corresponds to the current -/// behavior (do not skip the leak check) -- not the behavior we are -/// transitioning into. -#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] -pub enum SkipLeakCheck { - Yes, - #[default] - No, -} - -impl SkipLeakCheck { - fn is_yes(self) -> bool { - self == SkipLeakCheck::Yes - } -} - /// The mode that trait queries run in. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum TraitQueryMode { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index de08e7d2f0384..8fa8477b25935 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -24,7 +24,6 @@ use rustc_errors::{codes::*, DelayDm, Diagnostic}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; -use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; use rustc_span::{sym, ErrorGuaranteed, Span, DUMMY_SP}; @@ -460,7 +459,6 @@ fn report_conflicting_impls<'tcx>( Some(kind) => { let lint = match kind { FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS, - FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, }; tcx.node_span_lint( lint, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index e9a592bdee799..ca4c12b1dd5a1 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -11,7 +11,6 @@ pub use rustc_middle::traits::specialization_graph::*; #[derive(Copy, Clone, Debug)] pub enum FutureCompatOverlapErrorKind { Issue33140, - LeakCheck, } #[derive(Debug)] @@ -118,64 +117,31 @@ impl<'tcx> ChildrenExt<'tcx> for Children { } }; - let report_overlap_error = |overlap: traits::coherence::OverlapResult<'tcx>, - last_lint: &mut _| { - // Found overlap, but no specialization; error out or report future-compat warning. - - // Do we *still* get overlap if we disable the future-incompatible modes? - let should_err = traits::overlapping_impls( - tcx, - possible_sibling, - impl_def_id, - traits::SkipLeakCheck::default(), - overlap_mode, - ) - .is_some(); - - let error = create_overlap_error(overlap); - - if should_err { - Err(error) - } else { - *last_lint = Some(FutureCompatOverlapError { - error, - kind: FutureCompatOverlapErrorKind::LeakCheck, - }); - - Ok((false, false)) - } - }; - let last_lint_mut = &mut last_lint; - let (le, ge) = traits::overlapping_impls( - tcx, - possible_sibling, - impl_def_id, - traits::SkipLeakCheck::Yes, - overlap_mode, - ) - .map_or(Ok((false, false)), |overlap| { - if let Some(overlap_kind) = - tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) - { - match overlap_kind { - ty::ImplOverlapKind::Permitted { marker: _ } => {} - ty::ImplOverlapKind::Issue33140 => { - *last_lint_mut = Some(FutureCompatOverlapError { - error: create_overlap_error(overlap), - kind: FutureCompatOverlapErrorKind::Issue33140, - }); + let (le, ge) = + traits::overlapping_impls(tcx, possible_sibling, impl_def_id, overlap_mode) + .map_or(Ok((false, false)), |overlap| { + if let Some(overlap_kind) = + tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) + { + match overlap_kind { + ty::ImplOverlapKind::Permitted { marker: _ } => {} + ty::ImplOverlapKind::Issue33140 => { + *last_lint_mut = Some(FutureCompatOverlapError { + error: create_overlap_error(overlap), + kind: FutureCompatOverlapErrorKind::Issue33140, + }); + } + } + + return Ok((false, false)); } - } - - return Ok((false, false)); - } - let le = tcx.specializes((impl_def_id, possible_sibling)); - let ge = tcx.specializes((possible_sibling, impl_def_id)); + let le = tcx.specializes((impl_def_id, possible_sibling)); + let ge = tcx.specializes((possible_sibling, impl_def_id)); - if le == ge { report_overlap_error(overlap, last_lint_mut) } else { Ok((le, ge)) } - })?; + if le == ge { Err(create_overlap_error(overlap)) } else { Ok((le, ge)) } + })?; if le && !ge { debug!( diff --git a/tests/ui/codegen/subtyping-impacts-selection-1.rs b/tests/ui/codegen/subtyping-impacts-selection-1.rs index 09e06f6d6843b..0702f666a83c0 100644 --- a/tests/ui/codegen/subtyping-impacts-selection-1.rs +++ b/tests/ui/codegen/subtyping-impacts-selection-1.rs @@ -4,7 +4,6 @@ //[codegen] compile-flags: -Zmir-opt-level=0 // A regression test for #107205 -#![allow(coherence_leak_check)] struct Foo(T); fn useful<'a>(_: &'a u8) {} diff --git a/tests/ui/coherence/coherence-fn-implied-bounds.rs b/tests/ui/coherence/coherence-fn-implied-bounds.rs index 4539af9a32e38..0bf734d70722d 100644 --- a/tests/ui/coherence/coherence-fn-implied-bounds.rs +++ b/tests/ui/coherence/coherence-fn-implied-bounds.rs @@ -4,23 +4,15 @@ // bounds we ought to know that, in fact, `'a = 'b` must always hold, // and hence they are. // -// Rustc can't figure this out and hence it accepts the impls but -// gives a future-compatibility warning (because we'd like to make -// this an error someday). -// -// Note that while we would like to make this a hard error, we also -// give the same warning for `coherence-wasm-bindgen.rs`, which ought -// to be accepted. +// Rustc can't figure this out and hence it accepts the impls. This is +// a bit unfortunate as we will error here if we ever consider implied bounds +// when equating higher ranked types. -#![deny(coherence_leak_check)] +// check-pass trait Trait {} impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {} - -impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { - //~^ ERROR conflicting implementations - //~| WARNING this was previously accepted by the compiler -} +impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {} fn main() {} diff --git a/tests/ui/coherence/coherence-fn-implied-bounds.stderr b/tests/ui/coherence/coherence-fn-implied-bounds.stderr deleted file mode 100644 index b0dea74670925..0000000000000 --- a/tests/ui/coherence/coherence-fn-implied-bounds.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32` - --> $DIR/coherence-fn-implied-bounds.rs:21:1 - | -LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {} - | ------------------------------------------------------------------ first implementation here -LL | -LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -note: the lint level is defined here - --> $DIR/coherence-fn-implied-bounds.rs:15:9 - | -LL | #![deny(coherence_leak_check)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/coherence/coherence-free-vs-bound-region.rs b/tests/ui/coherence/coherence-free-vs-bound-region.rs index 2f5c49d293d5d..472048c8bb76f 100644 --- a/tests/ui/coherence/coherence-free-vs-bound-region.rs +++ b/tests/ui/coherence/coherence-free-vs-bound-region.rs @@ -1,21 +1,17 @@ // Capture a coherence pattern from wasm-bindgen that we discovered as part of -// future-compatibility warning #56105. This pattern currently receives a lint -// warning but we probably want to support it long term. +// future-compatibility warning #56105. This pattern pattern relies on coherence +// considering implementations to not overlap if there are universe errors. // // Key distinction: we are implementing once for `A` (take ownership) and one // for `&A` (borrow). // // c.f. #56105 -#![deny(coherence_leak_check)] +// check-pass trait TheTrait {} impl<'a> TheTrait for fn(&'a u8) {} - -impl TheTrait for fn(&u8) { - //~^ ERROR conflicting implementations of trait - //~| WARNING this was previously accepted by the compiler -} +impl TheTrait for fn(&u8) {} fn main() {} diff --git a/tests/ui/coherence/coherence-free-vs-bound-region.stderr b/tests/ui/coherence/coherence-free-vs-bound-region.stderr deleted file mode 100644 index c97b32e429d37..0000000000000 --- a/tests/ui/coherence/coherence-free-vs-bound-region.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: conflicting implementations of trait `TheTrait` for type `fn(&u8)` - --> $DIR/coherence-free-vs-bound-region.rs:16:1 - | -LL | impl<'a> TheTrait for fn(&'a u8) {} - | -------------------------------- first implementation here -LL | -LL | impl TheTrait for fn(&u8) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -note: the lint level is defined here - --> $DIR/coherence-free-vs-bound-region.rs:10:9 - | -LL | #![deny(coherence_leak_check)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/coherence/coherence-inherited-subtyping.rs b/tests/ui/coherence/coherence-inherited-subtyping.rs deleted file mode 100644 index f35cd2103da4a..0000000000000 --- a/tests/ui/coherence/coherence-inherited-subtyping.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Test that two distinct impls which match subtypes of one another -// yield coherence errors (or not) depending on the variance. -// -// Note: This scenario is currently accepted, but as part of the -// universe transition (#56105) may eventually become an error. - -struct Foo { - t: T, -} - -impl Foo fn(&'a u8, &'b u8) -> &'a u8> { - fn method1(&self) {} //~ ERROR duplicate definitions with name `method1` -} - -impl Foo fn(&'a u8, &'a u8) -> &'a u8> { - fn method1(&self) {} -} - -fn main() {} diff --git a/tests/ui/coherence/coherence-inherited-subtyping.stderr b/tests/ui/coherence/coherence-inherited-subtyping.stderr deleted file mode 100644 index 5c5753939049e..0000000000000 --- a/tests/ui/coherence/coherence-inherited-subtyping.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0592]: duplicate definitions with name `method1` - --> $DIR/coherence-inherited-subtyping.rs:12:5 - | -LL | fn method1(&self) {} - | ^^^^^^^^^^^^^^^^^ duplicate definitions for `method1` -... -LL | fn method1(&self) {} - | ----------------- other definition for `method1` - | - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0592`. diff --git a/tests/ui/coherence/coherence-inherited-universe-error.rs b/tests/ui/coherence/coherence-inherited-universe-error.rs new file mode 100644 index 0000000000000..21f1b604f9079 --- /dev/null +++ b/tests/ui/coherence/coherence-inherited-universe-error.rs @@ -0,0 +1,19 @@ +// Test that impls which are only distict due to +// universe errors are accepted. This was previously +// not the case. + +// check-pass + +struct Foo { + t: T, +} + +impl Foo fn(&'a u8, &'b u8) -> &'a u8> { + fn method1(&self) {} +} + +impl Foo fn(&'a u8, &'a u8) -> &'a u8> { + fn method1(&self) {} +} + +fn main() {} diff --git a/tests/ui/coherence/coherence-subtyping.rs b/tests/ui/coherence/coherence-subtyping.rs index b3ed728a81c06..5d0aea999a05f 100644 --- a/tests/ui/coherence/coherence-subtyping.rs +++ b/tests/ui/coherence/coherence-subtyping.rs @@ -1,8 +1,6 @@ -// Test that two distinct impls which match subtypes of one another -// yield coherence errors (or not) depending on the variance. -// -// Note: This scenario is currently accepted, but as part of the -// universe transition (#56105) may eventually become an error. +// Test that impls whose self types are subtypes of each other and +// which only differ due to a universe error are considered disjoint +// by coherence. // check-pass @@ -12,9 +10,6 @@ trait TheTrait { impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {} -impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - //~^ WARNING conflicting implementation - //~^^ WARNING this was previously accepted by the compiler but is being phased out -} +impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {} fn main() {} diff --git a/tests/ui/coherence/coherence-subtyping.stderr b/tests/ui/coherence/coherence-subtyping.stderr deleted file mode 100644 index 9d90019a50fd3..0000000000000 --- a/tests/ui/coherence/coherence-subtyping.stderr +++ /dev/null @@ -1,16 +0,0 @@ -warning: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` - --> $DIR/coherence-subtyping.rs:15:1 - | -LL | impl TheTrait for for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {} - | ---------------------------------------------------------- first implementation here -LL | -LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details - = note: `#[warn(coherence_leak_check)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/coherence/coherence-wasm-bindgen.rs b/tests/ui/coherence/coherence-wasm-bindgen.rs index ee09a72449be1..6ec576a309499 100644 --- a/tests/ui/coherence/coherence-wasm-bindgen.rs +++ b/tests/ui/coherence/coherence-wasm-bindgen.rs @@ -1,13 +1,8 @@ // Capture a coherence pattern from wasm-bindgen that we discovered as part of -// future-compatibility warning #56105. This pattern currently receives a lint -// warning but we probably want to support it long term. -// -// Key distinction: we are implementing once for `A` (take ownership) and one -// for `&A` (borrow). -// -// c.f. #56105 +// future-compatibility warning #56105. This pattern relies on universe +// errors impacting selection and is something we want to support. -#![deny(coherence_leak_check)] +// check-pass trait IntoWasmAbi { fn some_method(&self) {} @@ -30,8 +25,6 @@ where A: RefFromWasmAbi, R: ReturnWasmAbi, { - //~^^^^^ ERROR conflicting implementation - //~| WARNING this was previously accepted } fn main() {} diff --git a/tests/ui/coherence/coherence-wasm-bindgen.stderr b/tests/ui/coherence/coherence-wasm-bindgen.stderr deleted file mode 100644 index b3c3dac612dbd..0000000000000 --- a/tests/ui/coherence/coherence-wasm-bindgen.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn Fn(&_) -> _` - --> $DIR/coherence-wasm-bindgen.rs:28:1 - | -LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b) -LL | | where -LL | | A: FromWasmAbi, -LL | | R: ReturnWasmAbi, - | |_____________________- first implementation here -... -LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b) -LL | | where -LL | | A: RefFromWasmAbi, -LL | | R: ReturnWasmAbi, - | |_____________________^ conflicting implementation for `&dyn Fn(&_) -> _` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56105 - = note: downstream crates may implement trait `FromWasmAbi` for type `&_` - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -note: the lint level is defined here - --> $DIR/coherence-wasm-bindgen.rs:10:9 - | -LL | #![deny(coherence_leak_check)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr deleted file mode 100644 index 5368db293383c..0000000000000 --- a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: conflicting implementations of trait `FnMarker` for type `fn(&_)` - --> $DIR/negative-coherence-placeholder-region-constraints-on-unification.rs:21:1 - | -LL | impl FnMarker for fn(T) {} - | ------------------------------------------- first implementation here -LL | impl FnMarker for fn(&T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&_)` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details -note: the lint level is defined here - --> $DIR/negative-coherence-placeholder-region-constraints-on-unification.rs:4:11 - | -LL | #![forbid(coherence_leak_check)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs index 26d9d84d8f0c9..b1ecb12e49f02 100644 --- a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs +++ b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.rs @@ -1,7 +1,5 @@ // revisions: explicit implicit -//[implicit] check-pass - -#![forbid(coherence_leak_check)] +// check-pass #![feature(negative_impls, with_negative_coherence)] pub trait Marker {} @@ -19,7 +17,5 @@ trait FnMarker {} // as an assumption when proving `&'!0 T: Marker`... impl FnMarker for fn(T) {} impl FnMarker for fn(&T) {} -//[explicit]~^ ERROR conflicting implementations of trait `FnMarker` for type `fn(&_)` -//[explicit]~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! fn main() {} diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index f64e8b397987b..8b5e4aec0530d 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -2,10 +2,6 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!2_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index 8e852ec796ede..6a16ca9906e08 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -2,10 +2,6 @@ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Projection, AliasTy { args: [*const ?1t, RePlaceholder(!3_BoundRegion { var: 0, kind: BrNamed(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1), 'a) })], def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }) error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), _)>` for type `for<'a> fn(&'a (), _)` --> $DIR/associated-type.rs:31:1 | diff --git a/tests/ui/const-generics/invariant.rs b/tests/ui/const-generics/invariant.rs index 39d658be67d40..fb041b141bddd 100644 --- a/tests/ui/const-generics/invariant.rs +++ b/tests/ui/const-generics/invariant.rs @@ -12,8 +12,6 @@ impl SadBee for for<'a> fn(&'a ()) { const ASSOC: usize = 0; } impl SadBee for fn(&'static ()) { - //~^ WARNING conflicting implementations of trait - //~| WARNING this was previously accepted const ASSOC: usize = 100; } diff --git a/tests/ui/const-generics/invariant.stderr b/tests/ui/const-generics/invariant.stderr index f631e1311460f..2b66036798f02 100644 --- a/tests/ui/const-generics/invariant.stderr +++ b/tests/ui/const-generics/invariant.stderr @@ -1,19 +1,5 @@ -warning: conflicting implementations of trait `SadBee` for type `for<'a> fn(&'a ())` - --> $DIR/invariant.rs:14:1 - | -LL | impl SadBee for for<'a> fn(&'a ()) { - | ---------------------------------- first implementation here -... -LL | impl SadBee for fn(&'static ()) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a ())` - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details - = note: `#[warn(coherence_leak_check)]` on by default - error[E0308]: mismatched types - --> $DIR/invariant.rs:27:5 + --> $DIR/invariant.rs:25:5 | LL | v | ^ one type is more general than the other @@ -21,6 +7,6 @@ LL | v = note: expected reference `&Foo` found reference `&Foo fn(&'a ())>` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/higher-ranked/leak-check-in-selection.rs b/tests/ui/higher-ranked/leak-check-in-selection.rs index 5b36902ffdfe8..d8f83dbbc12aa 100644 --- a/tests/ui/higher-ranked/leak-check-in-selection.rs +++ b/tests/ui/higher-ranked/leak-check-in-selection.rs @@ -1,7 +1,6 @@ // run-pass // revisions: old next //[next] compile-flags: -Znext-solver -#![allow(coherence_leak_check)] trait Trait: Sized { fn is_higher_ranked(self) -> bool; diff --git a/tests/ui/mir/important-higher-ranked-regions.rs b/tests/ui/mir/important-higher-ranked-regions.rs index cadfb3b66f297..877c564b0c18c 100644 --- a/tests/ui/mir/important-higher-ranked-regions.rs +++ b/tests/ui/mir/important-higher-ranked-regions.rs @@ -3,7 +3,7 @@ // This test checks that bivariant parameters are handled correctly // in the mir. -#![allow(coherence_leak_check)] + trait Trait { type Assoc; } diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index c16a48d5f154c..489fa4daedc56 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -13,10 +13,6 @@ LL | #![feature(lazy_type_alias)] = note: see issue #112792 for more information = note: `#[warn(incomplete_features)]` on by default -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) -WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) From 1352b2ee193ea8852f6ef6bd57c79e9ad5b282da Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 23 Jan 2024 16:19:54 +0100 Subject: [PATCH 3/3] coolio --- .../src/traits/select/mod.rs | 11 ++-- .../trait-bounds/issue-30786-1.rs | 8 +-- .../trait-bounds/issue-30786-1.stderr | 59 +++++-------------- 3 files changed, 24 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 90a23cc9a2fc0..e84f6c7310e44 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -419,7 +419,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut no_candidates_apply = true; for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, c)?.may_apply() { + if self.evaluate_candidate(stack, c, false)?.may_apply() { no_candidates_apply = false; break; } @@ -490,7 +490,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // is needed for specialization. Propagate overflow if it occurs. let mut candidates = candidates .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { + .map(|c| match self.evaluate_candidate(stack, &c, false) { Ok(eval) if eval.may_apply() => { Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) } @@ -1234,7 +1234,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), + Ok(Some(c)) => self.evaluate_candidate(stack, &c, true), Ok(None) => Ok(EvaluatedToAmbig), Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical), Err(..) => Ok(EvaluatedToErr), @@ -1269,6 +1269,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, + leak_check_higher_ranked_goal: bool, ) -> Result { let mut result = self.evaluation_probe(|this, outer_universe| { // We eagerly instantiate higher ranked goals to prevent universe errors @@ -1281,7 +1282,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // in an overlap error in coherence. let p = self.infcx.instantiate_binder_with_placeholders(stack.obligation.predicate); let obligation = stack.obligation.with(this.tcx(), ty::Binder::dummy(p)); - *outer_universe = self.infcx.universe(); + if !leak_check_higher_ranked_goal { + *outer_universe = self.infcx.universe(); + } match this.confirm_candidate(&obligation, candidate.clone()) { Ok(selection) => { debug!(?selection); diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs index 349fae23a1ea4..27d7814c2a218 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.rs @@ -1,6 +1,6 @@ // normalize-stderr-test: "long-type-\d+" -> "long-type-hash" -// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream &'b mut A: Stream` // should act as assertion that item does not borrow from its stream; // but an earlier buggy rustc allowed `.map(|x: &_| x)` which does // have such an item. @@ -113,12 +113,8 @@ fn variant1() { // we deduce it somehow from a reuqirement that `Map: Stream` I // guess. let map = source.mapx(|x: &_| x); - //~^ ERROR implementation of `FnOnce` is not general enough let filter = map.filterx(|x: &_| true); - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough + //~^ ERROR the method `filterx` exists for struct } fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr index 3ad92de423f61..8ec5150491ace 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-30786-1.stderr @@ -1,50 +1,21 @@ -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-30786-1.rs:115:15 - | -LL | let map = source.mapx(|x: &_| x); - | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-30786-1.rs:117:18 - | -LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-30786-1.rs:117:18 +error[E0599]: the method `filterx` exists for struct `Map`, but its trait bounds were not satisfied + --> $DIR/issue-30786-1.rs:116:22 | +LL | pub struct Map { + | -------------------- method `filterx` not found for this struct because it doesn't satisfy `_: StreamExt` +... LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^ method cannot be called on `Map` due to unsatisfied trait bounds | - = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-30786-1.rs:117:18 - | -LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-30786-1.rs:117:18 - | -LL | let filter = map.filterx(|x: &_| true); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough +note: the following trait bounds were not satisfied: + `&'a mut &Map: Stream` + `&'a mut &mut Map: Stream` + `&'a mut Map: Stream` + --> $DIR/issue-30786-1.rs:98:50 | - = note: closure with signature `fn(&'2 u64) -> &u64` must implement `FnOnce<(&'1 u64,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 u64,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} + | --------- - ^^^^^^ unsatisfied trait bound introduced here -error: aborting due to 5 previous errors +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0599`.