Skip to content

Commit

Permalink
overflow errors: change source to a concrete enum
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed Jan 19, 2024
1 parent e6d20c3 commit d5e2221
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 67 deletions.
10 changes: 7 additions & 3 deletions compiler/rustc_trait_selection/src/solve/normalize.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt};
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
use rustc_data_structures::stack::ensure_sufficient_stack;
Expand Down Expand Up @@ -60,8 +60,12 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
let tcx = infcx.tcx;
let recursion_limit = tcx.recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
let ty::Alias(_, data) = *alias_ty.kind() else {
unreachable!();
};

self.at.infcx.err_ctxt().report_overflow_error(
&alias_ty,
OverflowCause::DeeplyNormalize(data),
self.at.cause.span,
true,
|_| {},
Expand Down Expand Up @@ -118,7 +122,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> {
let recursion_limit = tcx.recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
self.at.infcx.err_ctxt().report_overflow_error(
&ty::Const::new_unevaluated(tcx, uv, ty),
OverflowCause::DeeplyNormalize(ty::AliasTy::new(tcx, uv.def, uv.args)),
self.at.cause.span,
true,
|_| {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,26 @@ use super::{

pub use rustc_infer::traits::error_reporting::*;

pub enum OverflowCause<'tcx> {
DeeplyNormalize(ty::AliasTy<'tcx>),
TraitSolver(ty::Predicate<'tcx>),
}

pub trait TypeErrCtxtExt<'tcx> {
fn build_overflow_error<T>(
fn build_overflow_error(
&self,
predicate: &T,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
) -> DiagnosticBuilder<'tcx>
where
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
) -> DiagnosticBuilder<'tcx>;

fn report_overflow_error<T>(
fn report_overflow_error(
&self,
predicate: &T,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
mutate: impl FnOnce(&mut Diagnostic),
) -> !
where
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>;
) -> !;

fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;

Expand Down Expand Up @@ -241,17 +242,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
/// whose result could not be truly determined and thus we can't say
/// if the program type checks or not -- and they are unusual
/// occurrences in any case.
fn report_overflow_error<T>(
fn report_overflow_error(
&self,
predicate: &T,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
mutate: impl FnOnce(&mut Diagnostic),
) -> !
where
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit);
) -> ! {
let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
mutate(&mut err);
err.emit();

Expand All @@ -264,33 +262,52 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}

fn build_overflow_error<T>(
fn build_overflow_error(
&self,
predicate: &T,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
) -> DiagnosticBuilder<'tcx>
where
T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let predicate = self.resolve_vars_if_possible(predicate.clone());
let mut pred_str = predicate.to_string();

if pred_str.len() > 50 {
// We don't need to save the type to a file, we will be talking about this type already
// in a separate note when we explain the obligation, so it will be available that way.
let mut cx: FmtPrinter<'_, '_> =
FmtPrinter::new_with_limit(self.tcx, Namespace::TypeNS, rustc_session::Limit(6));
predicate.print(&mut cx).unwrap();
pred_str = cx.into_buffer();
) -> DiagnosticBuilder<'tcx> {
fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
where
T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let s = value.to_string();
if s.len() > 50 {
// We don't need to save the type to a file, we will be talking about this type already
// in a separate note when we explain the obligation, so it will be available that way.
let mut cx: FmtPrinter<'_, '_> =
FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
value.print(&mut cx).unwrap();
cx.into_buffer()
} else {
s
}
}
let mut err = struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow evaluating the requirement `{}`",
pred_str,
);

let mut err = match cause {
OverflowCause::DeeplyNormalize(alias_ty) => {
let alias_ty = self.resolve_vars_if_possible(alias_ty);
let kind = alias_ty.opt_kind(self.tcx).map_or("alias", |k| k.descr());
let alias_str = with_short_path(self.tcx, alias_ty);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow normalizing the {kind} `{alias_str}`",
)
}
OverflowCause::TraitSolver(predicate) => {
let predicate = self.resolve_vars_if_possible(predicate);
let pred_str = with_short_path(self.tcx, predicate);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow evaluating the requirement `{pred_str}`",
)
}
};

if suggest_increasing_limit {
self.suggest_new_overflow_limit(&mut err);
Expand All @@ -316,7 +333,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let predicate = obligation.predicate.clone().to_predicate(self.tcx);
let predicate = self.resolve_vars_if_possible(predicate);
self.report_overflow_error(
&predicate,
OverflowCause::TraitSolver(predicate),
obligation.cause.span,
suggest_increasing_limit,
|err| {
Expand Down Expand Up @@ -367,7 +384,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {

fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
let obligation = self.resolve_vars_if_possible(obligation);
let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true);
let mut err = self.build_overflow_error(
OverflowCause::TraitSolver(obligation.predicate),
obligation.cause.span,
true,
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,12 +435,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
.recursion_limit()
.value_within_limit(obligation.recursion_depth) =>
{
self.selcx.infcx.err_ctxt().report_overflow_error(
&obligation.predicate,
obligation.cause.span,
false,
|_| {},
);
self.selcx.infcx.err_ctxt().report_overflow_obligation(&obligation, false);
}

ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
Expand Down
10 changes: 4 additions & 6 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Code for projecting associated types out of trait references.

use super::check_args_compatible;
use super::error_reporting::OverflowCause;
use super::specialization_graph;
use super::translate_args;
use super::util;
Expand Down Expand Up @@ -516,10 +517,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
return ty;
}

let (kind, data) = match *ty.kind() {
ty::Alias(kind, alias_ty) => (kind, alias_ty),
_ => return ty.super_fold_with(self),
};
let ty::Alias(kind, data) = *ty.kind() else { return ty.super_fold_with(self) };

// We try to be a little clever here as a performance optimization in
// cases where there are nested projections under binders.
Expand Down Expand Up @@ -554,7 +552,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
self.selcx.infcx.err_ctxt().report_overflow_error(
&ty,
OverflowCause::DeeplyNormalize(data),
self.cause.span,
true,
|_| {},
Expand Down Expand Up @@ -664,7 +662,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.depth) {
self.selcx.infcx.err_ctxt().report_overflow_error(
&ty,
OverflowCause::DeeplyNormalize(data),
self.cause.span,
false,
|diag| {
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use crate::infer::at::At;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk};
use crate::traits::error_reporting::TypeErrCtxtExt;
use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt};
use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
use crate::traits::{ObligationCause, PredicateObligation, Reveal};
use rustc_data_structures::sso::SsoHashMap;
Expand Down Expand Up @@ -233,7 +233,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
let guar = self
.infcx
.err_ctxt()
.build_overflow_error(&ty, self.cause.span, true)
.build_overflow_error(
OverflowCause::DeeplyNormalize(data),
self.cause.span,
true,
)
.delay_as_bug();
return Ok(Ty::new_error(self.interner(), guar));
}
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_type_ir/src/ty_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ pub enum AliasKind {
Weak,
}

impl AliasKind {
pub fn descr(self) -> &'static str {
match self {
AliasKind::Projection => "associated type",
AliasKind::Inherent => "inherent associated type",
AliasKind::Opaque => "opaque type",
AliasKind::Weak => "type alias",
}
}
}

/// Defines the kinds of types used by the type system.
///
/// Types written by the user start out as `hir::TyKind` and get
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
error[E0275]: overflow evaluating the requirement `X2`
error[E0275]: overflow normalizing the type alias `X2`
--> $DIR/infinite-type-alias-mutual-recursion.rs:6:11
|
LL | type X1 = X2;
| ^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow evaluating the requirement `X3`
error[E0275]: overflow normalizing the type alias `X3`
--> $DIR/infinite-type-alias-mutual-recursion.rs:9:11
|
LL | type X2 = X3;
| ^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error[E0275]: overflow evaluating the requirement `X1`
error[E0275]: overflow normalizing the type alias `X1`
--> $DIR/infinite-type-alias-mutual-recursion.rs:11:11
|
LL | type X3 = X1;
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/infinite/infinite-type-alias-mutual-recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

type X1 = X2;
//[gated]~^ ERROR cycle detected when expanding type alias `X1`
//[feature]~^^ ERROR: overflow evaluating the requirement `X2`
//[feature]~^^ ERROR: overflow normalizing the type alias `X2`
type X2 = X3;
//[feature]~^ ERROR: overflow evaluating the requirement `X3`
//[feature]~^ ERROR: overflow normalizing the type alias `X3`
type X3 = X1;
//[feature]~^ ERROR: overflow evaluating the requirement `X1`
//[feature]~^ ERROR: overflow normalizing the type alias `X1`

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0275]: overflow evaluating the requirement `X`
error[E0275]: overflow normalizing the type alias `X`
--> $DIR/infinite-vec-type-recursion.rs:6:10
|
LL | type X = Vec<X>;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/infinite/infinite-vec-type-recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

type X = Vec<X>;
//[gated]~^ ERROR cycle detected
//[feature]~^^ ERROR: overflow evaluating the requirement `X`
//[feature]~^^ ERROR: overflow normalizing the type alias `X`

#[rustfmt::skip]
fn main() { let b: X = Vec::new(); }

0 comments on commit d5e2221

Please sign in to comment.