mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
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:
commit
0060db74f9
@ -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?
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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`.
|
@ -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(());
|
||||
}
|
@ -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`.
|
@ -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()
|
||||
}
|
||||
}
|
@ -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`.
|
Loading…
Reference in New Issue
Block a user