diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 1847847d9d2ae..553546b29e1e1 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -98,7 +98,33 @@ impl Qualif for HasMutInterior { } fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { - !ty.is_freeze(cx.tcx, cx.param_env) + // Avoid selecting for simple cases, such as builtin types. + if ty.is_trivially_freeze() { + return false; + } + + // We do not use `ty.is_freeze` here, because that requires revealing opaque types, which + // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error. + // Instead we invoke an obligation context manually, and provide the opaque type inference settings + // that allow the trait solver to just error out instead of cycling. + let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span)); + + let obligation = Obligation::new( + cx.tcx, + ObligationCause::dummy_with_span(cx.body.span), + cx.param_env, + ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]), + ); + + let infcx = cx + .tcx + .infer_ctxt() + .with_opaque_type_inference(cx.body.source.def_id().expect_local()) + .build(); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); + !errors.is_empty() } fn in_adt_inherently<'tcx>( diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 9af665cfb6fe0..b40247410010b 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1232,7 +1232,7 @@ impl<'tcx> Ty<'tcx> { /// /// Returning true means the type is known to be `Freeze`. Returning /// `false` means nothing -- could be `Freeze`, might not be. - fn is_trivially_freeze(self) -> bool { + pub fn is_trivially_freeze(self) -> bool { match self.kind() { ty::Int(_) | ty::Uint(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 10370c7898b0d..ce090d0cb8e7a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2382,13 +2382,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - // We can resolve the `impl Trait` to its concrete type, - // which enforces a DAG between the functions requiring - // the auto trait bounds in question. - match self.tcx().type_of_opaque(def_id) { - Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]), - Err(_) => { - return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); + if self.infcx.can_define_opaque_ty(def_id) { + // We cannot possibly resolve this opaque type, because we are currently computing its hidden type. + return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); + } else { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + match self.tcx().type_of_opaque(def_id) { + Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]), + Err(_) => { + return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); + } } } } diff --git a/tests/ui/const-generics/opaque_types.stderr b/tests/ui/const-generics/opaque_types.stderr index f03bca69a8bbf..c98e89121f6e4 100644 --- a/tests/ui/const-generics/opaque_types.stderr +++ b/tests/ui/const-generics/opaque_types.stderr @@ -109,8 +109,6 @@ note: ...which requires const checking `main::{constant#0}`... | LL | foo::<42>(); | ^^ - = note: ...which requires computing whether `Foo` is freeze... - = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`... = note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle note: cycle used when computing type of `Foo::{opaque#0}` --> $DIR/opaque_types.rs:3:12 diff --git a/tests/ui/impl-trait/rpit/const_check_false_cycle.current.stderr b/tests/ui/impl-trait/rpit/const_check_false_cycle.current.stderr deleted file mode 100644 index 78c7c164f590e..0000000000000 --- a/tests/ui/impl-trait/rpit/const_check_false_cycle.current.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0391]: cycle detected when computing type of opaque `f::{opaque#0}` - --> $DIR/const_check_false_cycle.rs:9:17 - | -LL | const fn f() -> impl Eq { - | ^^^^^^^ - | -note: ...which requires borrow-checking `f`... - --> $DIR/const_check_false_cycle.rs:9:1 - | -LL | const fn f() -> impl Eq { - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `f`... - --> $DIR/const_check_false_cycle.rs:9:1 - | -LL | const fn f() -> impl Eq { - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `f`... - --> $DIR/const_check_false_cycle.rs:9:1 - | -LL | const fn f() -> impl Eq { - | ^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing whether `f::{opaque#0}` is freeze... - = note: ...which requires evaluating trait selection obligation `f::{opaque#0}: core::marker::Freeze`... - = note: ...which again requires computing type of opaque `f::{opaque#0}`, completing the cycle -note: cycle used when computing type of `f::{opaque#0}` - --> $DIR/const_check_false_cycle.rs:9:17 - | -LL | const fn f() -> impl Eq { - | ^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/rpit/const_check_false_cycle.rs b/tests/ui/impl-trait/rpit/const_check_false_cycle.rs index 5b6b667e1faf6..d4ea0e3b14785 100644 --- a/tests/ui/impl-trait/rpit/const_check_false_cycle.rs +++ b/tests/ui/impl-trait/rpit/const_check_false_cycle.rs @@ -1,13 +1,12 @@ -//! This test causes a cycle error when checking whether the +//! This test caused a cycle error when checking whether the //! return type is `Freeze` during const checking, even though //! the information is readily available. //@ revisions: current next //@[next] compile-flags: -Znext-solver -//@[next] check-pass +//@ check-pass const fn f() -> impl Eq { - //[current]~^ ERROR cycle detected g() } const fn g() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs index 21197fcaa273a..d78c7cada3385 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs @@ -3,7 +3,6 @@ const fn test() -> impl ~const Fn() { //~^ ERROR `~const` can only be applied to `#[const_trait]` traits //~| ERROR `~const` can only be applied to `#[const_trait]` traits - //~| ERROR cycle detected const move || { //~ ERROR const closures are experimental let sl: &[u8] = b"foo"; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr index 2f8051109173d..1512029f0adef 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr @@ -1,5 +1,5 @@ error[E0658]: const closures are experimental - --> $DIR/ice-112822-expected-type-for-param.rs:7:5 + --> $DIR/ice-112822-expected-type-for-param.rs:6:5 | LL | const move || { | ^^^^^ @@ -23,7 +23,7 @@ LL | const fn test() -> impl ~const Fn() { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: can't compare `&u8` with `&u8` - --> $DIR/ice-112822-expected-type-for-param.rs:12:17 + --> $DIR/ice-112822-expected-type-for-param.rs:11:17 | LL | assert_eq!(first, &b'f'); | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&u8 == &u8` @@ -31,38 +31,7 @@ LL | assert_eq!(first, &b'f'); = help: the trait `~const PartialEq<&u8>` is not implemented for `&u8` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0391]: cycle detected when computing type of opaque `test::{opaque#0}` - --> $DIR/ice-112822-expected-type-for-param.rs:3:20 - | -LL | const fn test() -> impl ~const Fn() { - | ^^^^^^^^^^^^^^^^ - | -note: ...which requires borrow-checking `test`... - --> $DIR/ice-112822-expected-type-for-param.rs:3:1 - | -LL | const fn test() -> impl ~const Fn() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `test`... - --> $DIR/ice-112822-expected-type-for-param.rs:3:1 - | -LL | const fn test() -> impl ~const Fn() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `test`... - --> $DIR/ice-112822-expected-type-for-param.rs:3:1 - | -LL | const fn test() -> impl ~const Fn() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing whether `test::{opaque#0}` is freeze... - = note: ...which requires evaluating trait selection obligation `test::{opaque#0}: core::marker::Freeze`... - = note: ...which again requires computing type of opaque `test::{opaque#0}`, completing the cycle -note: cycle used when computing type of `test::{opaque#0}` - --> $DIR/ice-112822-expected-type-for-param.rs:3:20 - | -LL | const fn test() -> impl ~const Fn() { - | ^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0391, E0658. +Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.rs b/tests/ui/type-alias-impl-trait/in-where-clause.rs index 7c0de39c7c91c..6e104781d84f3 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.rs +++ b/tests/ui/type-alias-impl-trait/in-where-clause.rs @@ -4,7 +4,6 @@ #![feature(type_alias_impl_trait)] type Bar = impl Sized; //~^ ERROR: cycle -//~| ERROR: cycle fn foo() -> Bar where diff --git a/tests/ui/type-alias-impl-trait/in-where-clause.stderr b/tests/ui/type-alias-impl-trait/in-where-clause.stderr index 9c08b8f127d27..c486013f8874a 100644 --- a/tests/ui/type-alias-impl-trait/in-where-clause.stderr +++ b/tests/ui/type-alias-impl-trait/in-where-clause.stderr @@ -10,7 +10,7 @@ note: ...which requires computing type of opaque `Bar::{opaque#0}`... LL | type Bar = impl Sized; | ^^^^^^^^^^ note: ...which requires type-checking `foo`... - --> $DIR/in-where-clause.rs:9:1 + --> $DIR/in-where-clause.rs:8:1 | LL | / fn foo() -> Bar LL | | where @@ -25,26 +25,6 @@ LL | type Bar = impl Sized; | ^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}` - --> $DIR/in-where-clause.rs:5:12 - | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ - | -note: ...which requires type-checking `foo`... - --> $DIR/in-where-clause.rs:13:9 - | -LL | [0; 1 + 2] - | ^^^^^ - = note: ...which requires evaluating trait selection obligation `Bar: core::marker::Send`... - = note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle -note: cycle used when computing type of `Bar::{opaque#0}` - --> $DIR/in-where-clause.rs:5:12 - | -LL | type Bar = impl Sized; - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`.