Skip to content

Commit 8fbd78c

Browse files
Detect cycle errors hidden by opaques during monomorphization
1 parent e5fedce commit 8fbd78c

7 files changed

+147
-1
lines changed

compiler/rustc_traits/src/normalize_projection_ty.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ use rustc_infer::infer::TyCtxtInferExt;
33
use rustc_middle::query::Providers;
44
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
55
use rustc_trait_selection::infer::InferCtxtBuilderExt;
6+
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
67
use rustc_trait_selection::traits::query::{
78
normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution,
89
};
9-
use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
10+
use rustc_trait_selection::traits::{
11+
self, FulfillmentErrorCode, ObligationCause, SelectionContext,
12+
};
1013
use std::sync::atomic::Ordering;
1114

1215
pub(crate) fn provide(p: &mut Providers) {
@@ -40,6 +43,27 @@ fn normalize_projection_ty<'tcx>(
4043
&mut obligations,
4144
);
4245
ocx.register_obligations(obligations);
46+
// #112047: With projections and opaques, we are able to create opaques that
47+
// are recursive (given some substitution of the opaque's type variables).
48+
// In that case, we may only realize a cycle error when calling
49+
// `normalize_erasing_regions` in mono.
50+
if !ocx.infcx.next_trait_solver() {
51+
let errors = ocx.select_where_possible();
52+
if !errors.is_empty() {
53+
// Rustdoc may attempt to normalize type alias types which are not
54+
// well-formed. Rustdoc also normalizes types that are just not
55+
// well-formed, since we don't do as much HIR analysis (checking
56+
// that impl vars are constrained by the signature, for example).
57+
if !tcx.sess.opts.actually_rustdoc {
58+
for error in &errors {
59+
if let FulfillmentErrorCode::CodeCycle(cycle) = &error.code {
60+
ocx.infcx.err_ctxt().report_overflow_obligation_cycle(cycle);
61+
}
62+
}
63+
}
64+
return Err(NoSolution);
65+
}
66+
}
4367
// FIXME(associated_const_equality): All users of normalize_projection_ty expected
4468
// a type, but there is the possibility it could've been a const now. Maybe change
4569
// it to a Term later?
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// edition: 2021
2+
// build-fail
3+
//~^^ ERROR overflow evaluating the requirement `<A as Second>::{opaque#0} == _`
4+
5+
#![feature(async_fn_in_trait)]
6+
7+
fn main() {
8+
let _ = async {
9+
A.first().await.second().await;
10+
};
11+
}
12+
13+
pub trait First {
14+
type Second: Second;
15+
async fn first(self) -> Self::Second;
16+
}
17+
18+
struct A;
19+
20+
impl First for A {
21+
type Second = A;
22+
async fn first(self) -> Self::Second {
23+
A
24+
}
25+
}
26+
27+
pub trait Second {
28+
async fn second(self);
29+
}
30+
31+
impl<C> Second for C
32+
where
33+
C: First,
34+
{
35+
async fn second(self) {
36+
self.first().await.second().await;
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error[E0275]: overflow evaluating the requirement `<A as Second>::{opaque#0} == _`
2+
3+
error: aborting due to previous error
4+
5+
For more information about this error, try `rustc --explain E0275`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// edition: 2021
2+
// build-fail
3+
//~^^ ERROR overflow evaluating the requirement `<() as Recur>::Recur == _`
4+
5+
#![feature(impl_trait_in_assoc_type)]
6+
7+
use core::future::Future;
8+
9+
trait Recur {
10+
type Recur: Future<Output = ()>;
11+
12+
fn recur(self) -> Self::Recur;
13+
}
14+
15+
async fn recur(t: impl Recur) {
16+
t.recur().await;
17+
}
18+
19+
impl Recur for () {
20+
type Recur = impl Future<Output = ()>;
21+
22+
fn recur(self) -> Self::Recur {
23+
async move { recur(self).await; }
24+
}
25+
}
26+
27+
fn main() {
28+
recur(());
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error[E0275]: overflow evaluating the requirement `<() as Recur>::Recur == _`
2+
3+
error: aborting due to previous error
4+
5+
For more information about this error, try `rustc --explain E0275`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// edition: 2021
2+
// build-fail
3+
//~^^ ERROR overflow evaluating the requirement `<() as B>::Assoc == _`
4+
5+
#![feature(rustc_attrs)]
6+
#![feature(impl_trait_in_assoc_type)]
7+
8+
#[rustc_coinductive]
9+
trait A {
10+
type Assoc;
11+
12+
fn test() -> Self::Assoc;
13+
}
14+
15+
#[rustc_coinductive]
16+
trait B {
17+
type Assoc;
18+
19+
fn test() -> Self::Assoc;
20+
}
21+
22+
impl<T: A> B for T {
23+
type Assoc = impl Sized;
24+
25+
fn test() -> <Self as B>::Assoc {
26+
<T as A>::test()
27+
}
28+
}
29+
30+
fn main() {
31+
<() as A>::test();
32+
}
33+
34+
impl<T: B> A for T {
35+
type Assoc = impl Sized;
36+
37+
fn test() -> <Self as A>::Assoc {
38+
<T as B>::test()
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error[E0275]: overflow evaluating the requirement `<() as B>::Assoc == _`
2+
3+
error: aborting due to previous error
4+
5+
For more information about this error, try `rustc --explain E0275`.

0 commit comments

Comments
 (0)