Detect cycle errors hidden by opaques during monomorphization

This commit is contained in:
Michael Goulet 2023-09-13 17:33:40 +00:00
parent e5fedceabf
commit 8fbd78ccea
7 changed files with 147 additions and 1 deletions

View File

@ -3,10 +3,13 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::query::Providers;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::query::{
normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution,
};
use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
use rustc_trait_selection::traits::{
self, FulfillmentErrorCode, ObligationCause, SelectionContext,
};
use std::sync::atomic::Ordering;
pub(crate) fn provide(p: &mut Providers) {
@ -40,6 +43,27 @@ fn normalize_projection_ty<'tcx>(
&mut obligations,
);
ocx.register_obligations(obligations);
// #112047: With projections and opaques, we are able to create opaques that
// are recursive (given some substitution of the opaque's type variables).
// In that case, we may only realize a cycle error when calling
// `normalize_erasing_regions` in mono.
if !ocx.infcx.next_trait_solver() {
let errors = ocx.select_where_possible();
if !errors.is_empty() {
// Rustdoc may attempt to normalize type alias types which are not
// well-formed. Rustdoc also normalizes types that are just not
// well-formed, since we don't do as much HIR analysis (checking
// that impl vars are constrained by the signature, for example).
if !tcx.sess.opts.actually_rustdoc {
for error in &errors {
if let FulfillmentErrorCode::CodeCycle(cycle) = &error.code {
ocx.infcx.err_ctxt().report_overflow_obligation_cycle(cycle);
}
}
}
return Err(NoSolution);
}
}
// FIXME(associated_const_equality): All users of normalize_projection_ty expected
// a type, but there is the possibility it could've been a const now. Maybe change
// it to a Term later?

View File

@ -0,0 +1,38 @@
// edition: 2021
// build-fail
//~^^ ERROR overflow evaluating the requirement `<A as Second>::{opaque#0} == _`
#![feature(async_fn_in_trait)]
fn main() {
let _ = async {
A.first().await.second().await;
};
}
pub trait First {
type Second: Second;
async fn first(self) -> Self::Second;
}
struct A;
impl First for A {
type Second = A;
async fn first(self) -> Self::Second {
A
}
}
pub trait Second {
async fn second(self);
}
impl<C> Second for C
where
C: First,
{
async fn second(self) {
self.first().await.second().await;
}
}

View File

@ -0,0 +1,5 @@
error[E0275]: overflow evaluating the requirement `<A as Second>::{opaque#0} == _`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0275`.

View File

@ -0,0 +1,29 @@
// edition: 2021
// build-fail
//~^^ ERROR overflow evaluating the requirement `<() as Recur>::Recur == _`
#![feature(impl_trait_in_assoc_type)]
use core::future::Future;
trait Recur {
type Recur: Future<Output = ()>;
fn recur(self) -> Self::Recur;
}
async fn recur(t: impl Recur) {
t.recur().await;
}
impl Recur for () {
type Recur = impl Future<Output = ()>;
fn recur(self) -> Self::Recur {
async move { recur(self).await; }
}
}
fn main() {
recur(());
}

View File

@ -0,0 +1,5 @@
error[E0275]: overflow evaluating the requirement `<() as Recur>::Recur == _`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0275`.

View File

@ -0,0 +1,40 @@
// edition: 2021
// build-fail
//~^^ ERROR overflow evaluating the requirement `<() as B>::Assoc == _`
#![feature(rustc_attrs)]
#![feature(impl_trait_in_assoc_type)]
#[rustc_coinductive]
trait A {
type Assoc;
fn test() -> Self::Assoc;
}
#[rustc_coinductive]
trait B {
type Assoc;
fn test() -> Self::Assoc;
}
impl<T: A> B for T {
type Assoc = impl Sized;
fn test() -> <Self as B>::Assoc {
<T as A>::test()
}
}
fn main() {
<() as A>::test();
}
impl<T: B> A for T {
type Assoc = impl Sized;
fn test() -> <Self as A>::Assoc {
<T as B>::test()
}
}

View File

@ -0,0 +1,5 @@
error[E0275]: overflow evaluating the requirement `<() as B>::Assoc == _`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0275`.