Skip to content

Commit c43eb8e

Browse files
authored
Rollup merge of rust-lang#122192 - oli-obk:type_of_opaque_for_const_checks, r=lcnr
Do not try to reveal hidden types when trying to prove Freeze in the defining scope fixes rust-lang#99793 this avoids the cycle error by just causing a selection error, which is not fatal. We pessimistically assume that freeze does not hold, which is always a safe assumption.
2 parents a330e49 + ad6e85b commit c43eb8e

16 files changed

+211
-68
lines changed

compiler/rustc_const_eval/src/check_consts/qualifs.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,33 @@ impl Qualif for HasMutInterior {
100100
}
101101

102102
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
103-
!ty.is_freeze(cx.tcx, cx.param_env)
103+
// Avoid selecting for simple cases, such as builtin types.
104+
if ty.is_trivially_freeze() {
105+
return false;
106+
}
107+
108+
// We do not use `ty.is_freeze` here, because that requires revealing opaque types, which
109+
// requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error.
110+
// Instead we invoke an obligation context manually, and provide the opaque type inference settings
111+
// that allow the trait solver to just error out instead of cycling.
112+
let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span));
113+
114+
let obligation = Obligation::new(
115+
cx.tcx,
116+
ObligationCause::dummy_with_span(cx.body.span),
117+
cx.param_env,
118+
ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]),
119+
);
120+
121+
let infcx = cx
122+
.tcx
123+
.infer_ctxt()
124+
.with_opaque_type_inference(cx.body.source.def_id().expect_local())
125+
.build();
126+
let ocx = ObligationCtxt::new(&infcx);
127+
ocx.register_obligation(obligation);
128+
let errors = ocx.select_all_or_error();
129+
!errors.is_empty()
104130
}
105131

106132
fn in_adt_inherently<'tcx>(

compiler/rustc_middle/src/ty/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ impl<'tcx> Ty<'tcx> {
13021302
///
13031303
/// Returning true means the type is known to be `Freeze`. Returning
13041304
/// `false` means nothing -- could be `Freeze`, might not be.
1305-
fn is_trivially_freeze(self) -> bool {
1305+
pub fn is_trivially_freeze(self) -> bool {
13061306
match self.kind() {
13071307
ty::Int(_)
13081308
| ty::Uint(_)

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
777777
);
778778
}
779779

780-
ty::Alias(ty::Opaque, _) => {
780+
ty::Alias(ty::Opaque, alias) => {
781781
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) {
782782
// We do not generate an auto impl candidate for `impl Trait`s which already
783783
// reference our auto trait.
@@ -792,6 +792,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
792792
// We do not emit auto trait candidates for opaque types in coherence.
793793
// Doing so can result in weird dependency cycles.
794794
candidates.ambiguous = true;
795+
} else if self.infcx.can_define_opaque_ty(alias.def_id) {
796+
// We do not emit auto trait candidates for opaque types in their defining scope, as
797+
// we need to know the hidden type first, which we can't reliably know within the defining
798+
// scope.
799+
candidates.ambiguous = true;
795800
} else {
796801
candidates.vec.push(AutoImplCandidate)
797802
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,13 +2417,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
24172417
}
24182418

24192419
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
2420-
// We can resolve the `impl Trait` to its concrete type,
2421-
// which enforces a DAG between the functions requiring
2422-
// the auto trait bounds in question.
2423-
match self.tcx().type_of_opaque(def_id) {
2424-
Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
2425-
Err(_) => {
2426-
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
2420+
if self.infcx.can_define_opaque_ty(def_id) {
2421+
// We cannot possibly resolve this opaque type, because we are currently computing its hidden type.
2422+
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
2423+
} else {
2424+
// We can resolve the `impl Trait` to its concrete type,
2425+
// which enforces a DAG between the functions requiring
2426+
// the auto trait bounds in question.
2427+
match self.tcx().type_of_opaque(def_id) {
2428+
Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
2429+
Err(_) => {
2430+
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
2431+
}
24272432
}
24282433
}
24292434
}

tests/ui/const-generics/opaque_types.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ note: ...which requires const checking `main::{constant#0}`...
109109
|
110110
LL | foo::<42>();
111111
| ^^
112-
= note: ...which requires computing whether `Foo` is freeze...
113-
= note: ...which requires evaluating trait selection obligation `Foo: core::marker::Freeze`...
114112
= note: ...which again requires computing type of opaque `Foo::{opaque#0}`, completing the cycle
115113
note: cycle used when computing type of `Foo::{opaque#0}`
116114
--> $DIR/opaque_types.rs:3:12
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/auto-trait-selection-freeze.rs:19:16
3+
|
4+
LL | if false { is_trait(foo()) } else { Default::default() }
5+
| ^^^^^^^^ ----- type must be known at this point
6+
| |
7+
| cannot infer type of the type parameter `T` declared on the function `is_trait`
8+
|
9+
= note: cannot satisfy `_: Trait<_>`
10+
note: required by a bound in `is_trait`
11+
--> $DIR/auto-trait-selection-freeze.rs:11:16
12+
|
13+
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
14+
| ^^^^^^^^ required by this bound in `is_trait`
15+
help: consider specifying the generic arguments
16+
|
17+
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
18+
| ++++++++
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/auto-trait-selection-freeze.rs:19:16
3+
|
4+
LL | if false { is_trait(foo()) } else { Default::default() }
5+
| ^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `is_trait`
6+
|
7+
note: multiple `impl`s satisfying `impl Sized: Trait<_>` found
8+
--> $DIR/auto-trait-selection-freeze.rs:16:1
9+
|
10+
LL | impl<T: Freeze> Trait<u32> for T {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | impl<T> Trait<i32> for T {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^
14+
note: required by a bound in `is_trait`
15+
--> $DIR/auto-trait-selection-freeze.rs:11:16
16+
|
17+
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
18+
| ^^^^^^^^ required by this bound in `is_trait`
19+
help: consider specifying the generic arguments
20+
|
21+
LL | if false { is_trait::<_, U>(foo()) } else { Default::default() }
22+
| ++++++++
23+
24+
error: aborting due to 1 previous error
25+
26+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! This test shows how we fail selection in a way that can influence
2+
//! selection in a code path that succeeds.
3+
4+
//@ revisions: next old
5+
//@[next] compile-flags: -Znext-solver
6+
7+
#![feature(freeze)]
8+
9+
use std::marker::Freeze;
10+
11+
fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
12+
Default::default()
13+
}
14+
15+
trait Trait<T> {}
16+
impl<T: Freeze> Trait<u32> for T {}
17+
impl<T> Trait<i32> for T {}
18+
fn foo() -> impl Sized {
19+
if false { is_trait(foo()) } else { Default::default() }
20+
//~^ ERROR: type annotations needed
21+
}
22+
23+
fn main() {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/auto-trait-selection.rs:15:16
3+
|
4+
LL | if false { is_trait(foo()) } else { Default::default() }
5+
| ^^^^^^^^ ----- type must be known at this point
6+
| |
7+
| cannot infer type of the type parameter `T` declared on the function `is_trait`
8+
|
9+
= note: cannot satisfy `_: Trait<_>`
10+
note: required by a bound in `is_trait`
11+
--> $DIR/auto-trait-selection.rs:7:16
12+
|
13+
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
14+
| ^^^^^^^^ required by this bound in `is_trait`
15+
help: consider specifying the generic arguments
16+
|
17+
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
18+
| ++++++++
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0283]: type annotations needed
2+
--> $DIR/auto-trait-selection.rs:15:16
3+
|
4+
LL | if false { is_trait(foo()) } else { Default::default() }
5+
| ^^^^^^^^ cannot infer type of the type parameter `U` declared on the function `is_trait`
6+
|
7+
note: multiple `impl`s satisfying `impl Sized: Trait<_>` found
8+
--> $DIR/auto-trait-selection.rs:12:1
9+
|
10+
LL | impl<T: Send> Trait<u32> for T {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | impl<T> Trait<i32> for T {}
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^
14+
note: required by a bound in `is_trait`
15+
--> $DIR/auto-trait-selection.rs:7:16
16+
|
17+
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
18+
| ^^^^^^^^ required by this bound in `is_trait`
19+
help: consider specifying the generic arguments
20+
|
21+
LL | if false { is_trait::<_, U>(foo()) } else { Default::default() }
22+
| ++++++++
23+
24+
error: aborting due to 1 previous error
25+
26+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//! This test shows how we fail selection in a way that can influence
2+
//! selection in a code path that succeeds.
3+
4+
//@ revisions: next old
5+
//@[next] compile-flags: -Znext-solver
6+
7+
fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
8+
Default::default()
9+
}
10+
11+
trait Trait<T> {}
12+
impl<T: Send> Trait<u32> for T {}
13+
impl<T> Trait<i32> for T {}
14+
fn foo() -> impl Sized {
15+
if false { is_trait(foo()) } else { Default::default() }
16+
//~^ ERROR: type annotations needed
17+
}
18+
19+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//! This test caused a cycle error when checking whether the
2+
//! return type is `Freeze` during const checking, even though
3+
//! the information is readily available.
4+
5+
//@ revisions: current next
6+
//@[next] compile-flags: -Znext-solver
7+
//@ check-pass
8+
9+
const fn f() -> impl Eq {
10+
g()
11+
}
12+
const fn g() {}
13+
14+
fn main() {}

tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const fn test() -> impl ~const Fn() {
44
//~^ ERROR `~const` can only be applied to `#[const_trait]` traits
55
//~| ERROR `~const` can only be applied to `#[const_trait]` traits
6-
//~| ERROR cycle detected
76
const move || { //~ ERROR const closures are experimental
87
let sl: &[u8] = b"foo";
98

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0658]: const closures are experimental
2-
--> $DIR/ice-112822-expected-type-for-param.rs:7:5
2+
--> $DIR/ice-112822-expected-type-for-param.rs:6:5
33
|
44
LL | const move || {
55
| ^^^^^
@@ -23,46 +23,15 @@ LL | const fn test() -> impl ~const Fn() {
2323
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
2424

2525
error[E0277]: can't compare `&u8` with `&u8`
26-
--> $DIR/ice-112822-expected-type-for-param.rs:12:17
26+
--> $DIR/ice-112822-expected-type-for-param.rs:11:17
2727
|
2828
LL | assert_eq!(first, &b'f');
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&u8 == &u8`
3030
|
3131
= help: the trait `~const PartialEq<&u8>` is not implemented for `&u8`
3232
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
3333

34-
error[E0391]: cycle detected when computing type of opaque `test::{opaque#0}`
35-
--> $DIR/ice-112822-expected-type-for-param.rs:3:20
36-
|
37-
LL | const fn test() -> impl ~const Fn() {
38-
| ^^^^^^^^^^^^^^^^
39-
|
40-
note: ...which requires borrow-checking `test`...
41-
--> $DIR/ice-112822-expected-type-for-param.rs:3:1
42-
|
43-
LL | const fn test() -> impl ~const Fn() {
44-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45-
note: ...which requires promoting constants in MIR for `test`...
46-
--> $DIR/ice-112822-expected-type-for-param.rs:3:1
47-
|
48-
LL | const fn test() -> impl ~const Fn() {
49-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50-
note: ...which requires const checking `test`...
51-
--> $DIR/ice-112822-expected-type-for-param.rs:3:1
52-
|
53-
LL | const fn test() -> impl ~const Fn() {
54-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55-
= note: ...which requires computing whether `test::{opaque#0}` is freeze...
56-
= note: ...which requires evaluating trait selection obligation `test::{opaque#0}: core::marker::Freeze`...
57-
= note: ...which again requires computing type of opaque `test::{opaque#0}`, completing the cycle
58-
note: cycle used when computing type of `test::{opaque#0}`
59-
--> $DIR/ice-112822-expected-type-for-param.rs:3:20
60-
|
61-
LL | const fn test() -> impl ~const Fn() {
62-
| ^^^^^^^^^^^^^^^^
63-
= 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
64-
65-
error: aborting due to 5 previous errors
34+
error: aborting due to 4 previous errors
6635

67-
Some errors have detailed explanations: E0277, E0391, E0658.
36+
Some errors have detailed explanations: E0277, E0658.
6837
For more information about an error, try `rustc --explain E0277`.

tests/ui/type-alias-impl-trait/in-where-clause.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
#![feature(type_alias_impl_trait)]
55
type Bar = impl Sized;
66
//~^ ERROR: cycle
7-
//~| ERROR: cycle
87

98
fn foo() -> Bar
109
where
1110
Bar: Send,
11+
//~^ ERROR: type annotations needed
1212
{
1313
[0; 1 + 2]
1414
}

tests/ui/type-alias-impl-trait/in-where-clause.stderr

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ note: ...which requires computing type of opaque `Bar::{opaque#0}`...
1010
LL | type Bar = impl Sized;
1111
| ^^^^^^^^^^
1212
note: ...which requires type-checking `foo`...
13-
--> $DIR/in-where-clause.rs:9:1
13+
--> $DIR/in-where-clause.rs:8:1
1414
|
1515
LL | / fn foo() -> Bar
1616
LL | | where
@@ -25,26 +25,15 @@ LL | type Bar = impl Sized;
2525
| ^^^^^^^^^^
2626
= 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
2727

28-
error[E0391]: cycle detected when computing type of opaque `Bar::{opaque#0}`
29-
--> $DIR/in-where-clause.rs:5:12
30-
|
31-
LL | type Bar = impl Sized;
32-
| ^^^^^^^^^^
33-
|
34-
note: ...which requires type-checking `foo`...
35-
--> $DIR/in-where-clause.rs:13:9
28+
error[E0283]: type annotations needed: cannot satisfy `Bar: Send`
29+
--> $DIR/in-where-clause.rs:10:10
3630
|
37-
LL | [0; 1 + 2]
38-
| ^^^^^
39-
= note: ...which requires evaluating trait selection obligation `Bar: core::marker::Send`...
40-
= note: ...which again requires computing type of opaque `Bar::{opaque#0}`, completing the cycle
41-
note: cycle used when computing type of `Bar::{opaque#0}`
42-
--> $DIR/in-where-clause.rs:5:12
31+
LL | Bar: Send,
32+
| ^^^^
4333
|
44-
LL | type Bar = impl Sized;
45-
| ^^^^^^^^^^
46-
= 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
34+
= note: cannot satisfy `Bar: Send`
4735

4836
error: aborting due to 2 previous errors
4937

50-
For more information about this error, try `rustc --explain E0391`.
38+
Some errors have detailed explanations: E0283, E0391.
39+
For more information about an error, try `rustc --explain E0283`.

0 commit comments

Comments
 (0)