Rollup merge of #115801 - compiler-errors:async-cycle-mono, r=oli-obk

Detect cycle errors hidden by opaques during monomorphization

Opaque types may reveal to projections, which themselves normalize to opaques. We don't currently normalize when checking that opaques are cyclical, and we may also not know that the opaque is cyclical until monomorphization (see `tests/ui/type-alias-impl-trait/mututally-recursive-overflow.rs`).

Detect cycle errors in `normalize_projection_ty` and report a fatal overflow (in the old solver). Luckily, this is already detected as a fatal overflow in the new solver.

Fixes #112047
This commit is contained in:
Guillaume Gomez 2023-09-19 20:23:19 +02:00 committed by GitHub
commit 0060db74f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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::query::Providers;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::query::{ use rustc_trait_selection::traits::query::{
normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution, 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; use std::sync::atomic::Ordering;
pub(crate) fn provide(p: &mut Providers) { pub(crate) fn provide(p: &mut Providers) {
@ -40,6 +43,27 @@ fn normalize_projection_ty<'tcx>(
&mut obligations, &mut obligations,
); );
ocx.register_obligations(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 // 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 // a type, but there is the possibility it could've been a const now. Maybe change
// it to a Term later? // 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`.