Skip to content

Commit

Permalink
Unrolled build for rust-lang#115801
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#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 rust-lang#112047
  • Loading branch information
rust-timer authored Sep 19, 2023
2 parents 42f5828 + 8fbd78c commit 64d2330
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 1 deletion.
26 changes: 25 additions & 1 deletion compiler/rustc_traits/src/normalize_projection_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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?
Expand Down
38 changes: 38 additions & 0 deletions tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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`.
29 changes: 29 additions & 0 deletions tests/ui/type-alias-impl-trait/indirect-recursion-issue-112047.rs
Original file line number Diff line number Diff line change
@@ -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(());
}
Original file line number Diff line number Diff line change
@@ -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`.
40 changes: 40 additions & 0 deletions tests/ui/type-alias-impl-trait/mututally-recursive-overflow.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 64d2330

Please sign in to comment.