From a3c3871e1d47bb40c3ba1ada7707524a1c214181 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 7 May 2021 20:00:17 +0200 Subject: [PATCH 1/2] update auto trait handling --- .../src/traits/select/candidate_assembly.rs | 51 ++++- .../src/traits/select/mod.rs | 25 ++- src/test/ui/auto-traits/issue-83857-ub.rs | 29 +++ src/test/ui/auto-traits/issue-83857-ub.stderr | 16 ++ src/test/ui/generator/auto-trait-regions.rs | 6 +- src/test/ui/impl-trait/auto-trait-leak.rs | 2 + src/test/ui/impl-trait/auto-trait-leak.stderr | 188 +++++++++++++++++- .../recursive-impl-trait-type-indirect.rs | 1 - .../recursive-impl-trait-type-indirect.stderr | 67 +++++-- .../auto-trait-leakage3.rs | 2 + .../auto-trait-leakage3.stderr | 40 +++- .../type-alias-impl-trait/inference-cycle.rs | 2 + .../inference-cycle.stderr | 42 +++- 13 files changed, 419 insertions(+), 52 deletions(-) create mode 100644 src/test/ui/auto-traits/issue-83857-ub.rs create mode 100644 src/test/ui/auto-traits/issue-83857-ub.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index b573c4b43906c..8c352f69e9f26 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -332,11 +332,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_from_projected_tys(obligation, &mut candidates); self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Auto implementations have lower priority, so we only - // consider triggering a default if there is no other impl that can apply. - if candidates.vec.is_empty() { - self.assemble_candidates_from_auto_impls(obligation, &mut candidates); - } + self.assemble_candidates_from_auto_impls(obligation, &mut candidates); } debug!("candidate list size: {}", candidates.vec.len()); Ok(candidates) @@ -600,7 +596,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // for an example of a test case that exercises // this path. } - ty::Infer(ty::TyVar(_)) => { + ty::Infer(ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_)) => { // The auto impl might apply; we don't know. candidates.ambiguous = true; } @@ -620,7 +616,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - _ => candidates.vec.push(AutoImplCandidate(def_id)), + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!( + "asked to assemble auto trait candidates of unexpected type: {:?}", + self_ty + ); + } + + // Only consider auto impls if there are no manual impls for the root of `self_ty`. + // + // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl + // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls + // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined. + // + // Generally, we have to guarantee that for all `SimplifiedType`s the only crate + // which may define impls for that type is either the crate defining the type + // or the trait. This should be guaranteed by the orphan check. + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::Adt(..) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Closure(_, _) + | ty::Generator(..) + | ty::Never + | ty::Tuple(_) + | ty::Opaque(_, _) + | ty::GeneratorWitness(_) => { + if self.tcx().find_map_relevant_impl(def_id, self_ty, |_| Some(())).is_none() { + candidates.vec.push(AutoImplCandidate(def_id)) + } + } + ty::Error(_) => {} // do not add an auto trait impl for `ty::Error` for now. } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 1414c742635c4..2c1a32abf25ad 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1518,6 +1518,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// candidates and prefer where-clause candidates. /// /// See the comment for "SelectionCandidate" for more details. + #[instrument(level = "debug", skip(self, needs_infer))] fn candidate_should_be_dropped_in_favor_of( &mut self, sized_predicate: bool, @@ -1542,13 +1543,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. match (&other.candidate, &victim.candidate) { - (_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // (*) ( BuiltinCandidate { has_nested: false } @@ -1610,6 +1604,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ( ParamCandidate(ref cand), ImplCandidate(..) + | AutoImplCandidate(_) | ClosureCandidate | GeneratorCandidate | FnPointerCandidate { .. } @@ -1621,6 +1616,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) => !is_global(cand), ( ImplCandidate(_) + | AutoImplCandidate(_) | ClosureCandidate | GeneratorCandidate | FnPointerCandidate { .. } @@ -1651,6 +1647,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ( ObjectCandidate(_) | ProjectionCandidate(_), ImplCandidate(..) + | AutoImplCandidate(_) | ClosureCandidate | GeneratorCandidate | FnPointerCandidate { .. } @@ -1663,6 +1660,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ( ImplCandidate(..) + | AutoImplCandidate(_) | ClosureCandidate | GeneratorCandidate | FnPointerCandidate { .. } @@ -1741,6 +1739,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + (AutoImplCandidate(_), ImplCandidate(_)) | (ImplCandidate(_), AutoImplCandidate(_)) => { + false + } + + (AutoImplCandidate(_), _) | (_, AutoImplCandidate(_)) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other global candidates: {:?} {:?}", + other, + victim + ); + } + // Everything else is ambiguous ( ImplCandidate(_) diff --git a/src/test/ui/auto-traits/issue-83857-ub.rs b/src/test/ui/auto-traits/issue-83857-ub.rs new file mode 100644 index 0000000000000..4a38a6fff8d5b --- /dev/null +++ b/src/test/ui/auto-traits/issue-83857-ub.rs @@ -0,0 +1,29 @@ +struct Always(T, U); +unsafe impl Send for Always {} +struct Foo(Always); + +trait False {} +unsafe impl Send for Foo {} + +trait WithAssoc { + type Output; +} +impl WithAssoc for T { + type Output = Self; +} +impl WithAssoc for Foo { + type Output = Box; +} + +fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) { + //~^ ERROR `Foo` cannot be sent between threads safely + f(foo(v)); +} + +fn foo(x: T) -> ::Output { + x +} + +fn main() { + generic(Foo(Always(0, ())), |b| *b); +} diff --git a/src/test/ui/auto-traits/issue-83857-ub.stderr b/src/test/ui/auto-traits/issue-83857-ub.stderr new file mode 100644 index 0000000000000..3c2a521c61033 --- /dev/null +++ b/src/test/ui/auto-traits/issue-83857-ub.stderr @@ -0,0 +1,16 @@ +error[E0277]: `Foo` cannot be sent between threads safely + --> $DIR/issue-83857-ub.rs:18:38 + | +LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `Foo` + = note: required because of the requirements on the impl of `WithAssoc` for `Foo` +help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement + | +LL | fn generic(v: Foo, f: fn( as WithAssoc>::Output) -> i32) where Foo: Send { + | +++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs index 8f1e4f1b66f48..59e4118ca0f91 100644 --- a/src/test/ui/generator/auto-trait-regions.rs +++ b/src/test/ui/generator/auto-trait-regions.rs @@ -23,7 +23,7 @@ fn assert_foo(f: T) {} fn main() { // Make sure 'static is erased for generator interiors so we can't match it in trait selection let x: &'static _ = &OnlyFooIfStaticRef(No); - let gen = || { + let gen = move || { let x = x; yield; assert_foo(x); @@ -34,7 +34,7 @@ fn main() { // Allow impls which matches any lifetime let x = &OnlyFooIfRef(No); - let gen = || { + let gen = move || { let x = x; yield; assert_foo(x); @@ -42,7 +42,7 @@ fn main() { assert_foo(gen); // ok // Disallow impls which relates lifetimes in the generator interior - let gen = || { + let gen = move || { let a = A(&mut true, &mut true, No); yield; assert_foo(a); diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs index c2fbbf94fd666..e8541c565aee6 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.rs +++ b/src/test/ui/impl-trait/auto-trait-leak.rs @@ -11,6 +11,8 @@ fn main() { // return type, which can't depend on the obligation. fn cycle1() -> impl Clone { //~^ ERROR cycle detected + //~| ERROR cycle detected + //~| ERROR cycle detected send(cycle2().clone()); Rc::new(Cell::new(5)) diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 634ff14869eb4..69988eb997c0f 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -30,43 +30,43 @@ note: ...which requires building MIR for `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle1`... - --> $DIR/auto-trait-leak.rs:14:5 + --> $DIR/auto-trait-leak.rs:16:5 | LL | send(cycle2().clone()); | ^^^^ = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... - --> $DIR/auto-trait-leak.rs:19:16 + --> $DIR/auto-trait-leak.rs:21:16 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ note: ...which requires borrow-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:19:1 + --> $DIR/auto-trait-leak.rs:21:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... - --> $DIR/auto-trait-leak.rs:19:1 + --> $DIR/auto-trait-leak.rs:21:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:19:1 + --> $DIR/auto-trait-leak.rs:21:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires unsafety-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:19:1 + --> $DIR/auto-trait-leak.rs:21:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires building MIR for `cycle2`... - --> $DIR/auto-trait-leak.rs:19:1 + --> $DIR/auto-trait-leak.rs:21:1 | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires type-checking `cycle2`... - --> $DIR/auto-trait-leak.rs:20:5 + --> $DIR/auto-trait-leak.rs:22:5 | LL | send(cycle1().clone()); | ^^^^ @@ -84,6 +84,176 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error: aborting due to previous error +error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` + --> $DIR/auto-trait-leak.rs:12:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:16:5 + | +LL | send(cycle2().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... +note: ...which requires computing type of `cycle2::{opaque#0}`... + --> $DIR/auto-trait-leak.rs:21:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/auto-trait-leak.rs:1:1 + | +LL | / use std::cell::Cell; +LL | | use std::rc::Rc; +LL | | +LL | | fn send(_: T) {} +... | +LL | | Rc::new(String::from("foo")) +LL | | } + | |_^ + +error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` + --> $DIR/auto-trait-leak.rs:12:16 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^ + | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:16:5 + | +LL | send(cycle2().clone()); + | ^^^^ + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... +note: ...which requires computing type of `cycle2::{opaque#0}`... + --> $DIR/auto-trait-leak.rs:21:16 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:21:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/auto-trait-leak.rs:1:1 + | +LL | / use std::cell::Cell; +LL | | use std::rc::Rc; +LL | | +LL | | fn send(_: T) {} +... | +LL | | Rc::new(String::from("foo")) +LL | | } + | |_^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs index e3c621f0c5742..d7786ececa890 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -89,7 +89,6 @@ fn mutual_recursion() -> impl Sync { } fn mutual_recursion_b() -> impl Sized { - //~^ ERROR mutual_recursion() } diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index b9b2ce249f7bf..b13758c01aff2 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -119,30 +119,57 @@ LL | | x; LL | | } | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6]` -error[E0720]: cannot resolve opaque type +error[E0391]: cycle detected when computing type of `mutual_recursion::{opaque#0}` --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 | LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^ recursive opaque type -LL | -LL | mutual_recursion_b() - | -------------------- returning here with type `impl Sized` -... -LL | fn mutual_recursion_b() -> impl Sized { - | ---------- returning this opaque type `impl Sized` - -error[E0720]: cannot resolve opaque type - --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 + | ^^^^^^^^^ + | +note: ...which requires borrow-checking `mutual_recursion`... + --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 | LL | fn mutual_recursion() -> impl Sync { - | --------- returning this opaque type `impl Sync` -... -LL | fn mutual_recursion_b() -> impl Sized { - | ^^^^^^^^^^ recursive opaque type -LL | -LL | mutual_recursion() - | ------------------ returning here with type `impl Sync` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `mutual_recursion`... + --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing MIR for `mutual_recursion`... + --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `mutual_recursion`... + --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for `mutual_recursion`... + --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `mutual_recursion`... + --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 + | +LL | fn mutual_recursion() -> impl Sync { + | ^^^^^^^^^ + = note: ...which requires evaluating trait selection obligation `impl Sized: core::marker::Sync`... + = note: ...which again requires computing type of `mutual_recursion::{opaque#0}`, completing the cycle +note: cycle used when checking item types in top-level module + --> $DIR/recursive-impl-trait-type-indirect.rs:4:1 + | +LL | / #![feature(generators)] +LL | | #![allow(unconditional_recursion)] +LL | | +LL | | fn option(i: i32) -> impl Sized { +... | +LL | | +LL | | fn main() {} + | |____________^ -error: aborting due to 14 previous errors +error: aborting due to 13 previous errors -For more information about this error, try `rustc --explain E0720`. +Some errors have detailed explanations: E0391, E0720. +For more information about an error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs index 5fb7a9473d3df..b699d060006b5 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs @@ -6,6 +6,8 @@ mod m { type Foo = impl std::fmt::Debug; //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] + //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] + //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] pub fn foo() -> Foo { 22_u32 diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr index c0147e56c9364..d9d29c16a8042 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr @@ -5,7 +5,7 @@ LL | type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/auto-trait-leakage3.rs:15:9 + --> $DIR/auto-trait-leakage3.rs:17:9 | LL | is_send(foo()); | ^^^^^^^ @@ -17,6 +17,42 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ -error: aborting due to previous error +error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` + --> $DIR/auto-trait-leakage3.rs:7:16 + | +LL | type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `m::bar`... + --> $DIR/auto-trait-leakage3.rs:16:5 + | +LL | pub fn bar() { + | ^^^^^^^^^^^^ + = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in module `m` + --> $DIR/auto-trait-leakage3.rs:6:1 + | +LL | mod m { + | ^^^^^ + +error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` + --> $DIR/auto-trait-leakage3.rs:7:16 + | +LL | type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `m::bar`... + --> $DIR/auto-trait-leakage3.rs:16:5 + | +LL | pub fn bar() { + | ^^^^^^^^^^^^ + = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in module `m` + --> $DIR/auto-trait-leakage3.rs:6:1 + | +LL | mod m { + | ^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.rs b/src/test/ui/type-alias-impl-trait/inference-cycle.rs index c781e200bf8ee..ea4657e6e68f0 100644 --- a/src/test/ui/type-alias-impl-trait/inference-cycle.rs +++ b/src/test/ui/type-alias-impl-trait/inference-cycle.rs @@ -4,6 +4,8 @@ mod m { type Foo = impl std::fmt::Debug; //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] + //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] + //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391] // Cycle: error today, but it'd be nice if it eventually worked diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr index e12124664778e..d7f6647622932 100644 --- a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr +++ b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr @@ -5,7 +5,7 @@ LL | type Foo = impl std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^ | note: ...which requires type-checking `m::bar`... - --> $DIR/inference-cycle.rs:15:9 + --> $DIR/inference-cycle.rs:17:9 | LL | is_send(foo()); // Today: error | ^^^^^^^ @@ -17,8 +17,44 @@ note: cycle used when checking item types in module `m` LL | mod m { | ^^^^^ +error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` + --> $DIR/inference-cycle.rs:5:16 + | +LL | type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `m::bar`... + --> $DIR/inference-cycle.rs:16:5 + | +LL | pub fn bar() { + | ^^^^^^^^^^^^ + = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in module `m` + --> $DIR/inference-cycle.rs:4:1 + | +LL | mod m { + | ^^^^^ + +error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}` + --> $DIR/inference-cycle.rs:5:16 + | +LL | type Foo = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires type-checking `m::bar`... + --> $DIR/inference-cycle.rs:16:5 + | +LL | pub fn bar() { + | ^^^^^^^^^^^^ + = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle +note: cycle used when checking item types in module `m` + --> $DIR/inference-cycle.rs:4:1 + | +LL | mod m { + | ^^^^^ + error[E0308]: mismatched types - --> $DIR/inference-cycle.rs:19:22 + --> $DIR/inference-cycle.rs:21:22 | LL | type Foo = impl std::fmt::Debug; | -------------------- the expected opaque type @@ -31,7 +67,7 @@ LL | let f: Foo = 22_u32; = note: expected opaque type `impl Debug` found type `u32` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0308, E0391. For more information about an error, try `rustc --explain E0308`. From b3e6d513f7272614ab790aedbdf08aa4f05445a7 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 19 Jan 2022 17:35:26 +0100 Subject: [PATCH 2/2] deal with opaque types without cycling --- .../src/traits/select/candidate_assembly.rs | 32 ++++++--- .../ui/impl-trait/recursive-auto-trait.rs | 10 +++ .../recursive-impl-trait-type-indirect.rs | 1 + .../recursive-impl-trait-type-indirect.stderr | 67 ++++++------------- 4 files changed, 54 insertions(+), 56 deletions(-) create mode 100644 src/test/ui/impl-trait/recursive-auto-trait.rs diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 8c352f69e9f26..b8437756c6970 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -625,15 +625,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } - // Only consider auto impls if there are no manual impls for the root of `self_ty`. - // - // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl - // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls - // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined. - // - // Generally, we have to guarantee that for all `SimplifiedType`s the only crate - // which may define impls for that type is either the crate defining the type - // or the trait. This should be guaranteed by the orphan check. + ty::Opaque(_, _) + if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) => + { + // We do not generate an auto impl candidate for `impl Trait`s which already + // reference our auto trait. + // + // For example during candidate assembly for `impl Send: Send`, we don't have + // to look at the constituent types for this opaque types to figure out that this + // trivially holds. + // + // Note that this is only sound as projection candidates of opaque types + // are always applicable for auto traits. + } + ty::Bool | ty::Char | ty::Int(_) @@ -653,6 +658,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Tuple(_) | ty::Opaque(_, _) | ty::GeneratorWitness(_) => { + // Only consider auto impls if there are no manual impls for the root of `self_ty`. + // + // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl + // for `&SomeType: Auto` exists. Due to E0321 the only crate where impls + // for `&SomeType: Auto` can be defined is the crate where `Auto` has been defined. + // + // Generally, we have to guarantee that for all `SimplifiedType`s the only crate + // which may define impls for that type is either the crate defining the type + // or the trait. This should be guaranteed by the orphan check. if self.tcx().find_map_relevant_impl(def_id, self_ty, |_| Some(())).is_none() { candidates.vec.push(AutoImplCandidate(def_id)) } diff --git a/src/test/ui/impl-trait/recursive-auto-trait.rs b/src/test/ui/impl-trait/recursive-auto-trait.rs new file mode 100644 index 0000000000000..d7b68144ff6ba --- /dev/null +++ b/src/test/ui/impl-trait/recursive-auto-trait.rs @@ -0,0 +1,10 @@ +// check-pass +fn is_send(_: T) {} +fn foo() -> impl Send { + if false { + is_send(foo()); + } + () +} + +fn main() {} diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs index d7786ececa890..e3c621f0c5742 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -89,6 +89,7 @@ fn mutual_recursion() -> impl Sync { } fn mutual_recursion_b() -> impl Sized { + //~^ ERROR mutual_recursion() } diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index b13758c01aff2..b9b2ce249f7bf 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -119,57 +119,30 @@ LL | | x; LL | | } | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6]` -error[E0391]: cycle detected when computing type of `mutual_recursion::{opaque#0}` +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 | LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^ - | -note: ...which requires borrow-checking `mutual_recursion`... - --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 - | -LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing `mutual_recursion`... - --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 - | -LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires processing MIR for `mutual_recursion`... - --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 - | -LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires unsafety-checking `mutual_recursion`... - --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 - | -LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `mutual_recursion`... - --> $DIR/recursive-impl-trait-type-indirect.rs:86:1 - | -LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `mutual_recursion`... - --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 + | ^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion_b() + | -------------------- returning here with type `impl Sized` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ---------- returning this opaque type `impl Sized` + +error[E0720]: cannot resolve opaque type + --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 | LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^ - = note: ...which requires evaluating trait selection obligation `impl Sized: core::marker::Sync`... - = note: ...which again requires computing type of `mutual_recursion::{opaque#0}`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/recursive-impl-trait-type-indirect.rs:4:1 - | -LL | / #![feature(generators)] -LL | | #![allow(unconditional_recursion)] -LL | | -LL | | fn option(i: i32) -> impl Sized { -... | -LL | | -LL | | fn main() {} - | |____________^ + | --------- returning this opaque type `impl Sync` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion() + | ------------------ returning here with type `impl Sync` -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0391, E0720. -For more information about an error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0720`.