mirror of https://github.com/rust-lang/rust.git
Split out overflow handling into its own module
This commit is contained in:
parent
a2d58197a7
commit
7af825fea4
|
@ -3,6 +3,7 @@
|
|||
pub mod ambiguity;
|
||||
mod infer_ctxt_ext;
|
||||
pub mod on_unimplemented;
|
||||
mod overflow;
|
||||
pub mod suggestions;
|
||||
mod type_err_ctxt_ext;
|
||||
|
||||
|
@ -17,6 +18,7 @@ use rustc_span::Span;
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
pub use self::infer_ctxt_ext::*;
|
||||
pub use self::overflow::*;
|
||||
pub use self::type_err_ctxt_ext::*;
|
||||
|
||||
// When outputting impl candidates, prefer showing those that are more similar.
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_errors::{
|
||||
struct_span_code_err, Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, E0275,
|
||||
};
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_infer::traits::{Obligation, PredicateObligation};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::ty::print::{FmtPrinter, Print};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::Span;
|
||||
use rustc_type_ir::Upcast;
|
||||
|
||||
use super::InferCtxtPrivExt;
|
||||
use crate::error_reporting::traits::suggestions::TypeErrCtxtExt;
|
||||
|
||||
pub enum OverflowCause<'tcx> {
|
||||
DeeplyNormalize(ty::AliasTerm<'tcx>),
|
||||
TraitSolver(ty::Predicate<'tcx>),
|
||||
}
|
||||
|
||||
pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diag<'_, G>,
|
||||
) {
|
||||
let suggested_limit = match tcx.recursion_limit() {
|
||||
Limit(0) => Limit(2),
|
||||
limit => limit * 2,
|
||||
};
|
||||
err.help(format!(
|
||||
"consider increasing the recursion limit by adding a \
|
||||
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
|
||||
suggested_limit,
|
||||
tcx.crate_name(LOCAL_CRATE),
|
||||
));
|
||||
}
|
||||
|
||||
#[extension(pub trait TypeErrCtxtOverflowExt<'a, 'tcx>)]
|
||||
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
/// Reports that an overflow has occurred and halts compilation. We
|
||||
/// halt compilation unconditionally because it is important that
|
||||
/// overflows never be masked -- they basically represent computations
|
||||
/// 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(
|
||||
&self,
|
||||
cause: OverflowCause<'tcx>,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
mutate: impl FnOnce(&mut Diag<'_>),
|
||||
) -> ! {
|
||||
let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
|
||||
mutate(&mut err);
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
fn build_overflow_error(
|
||||
&self,
|
||||
cause: OverflowCause<'tcx>,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> Diag<'a> {
|
||||
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 = match cause {
|
||||
OverflowCause::DeeplyNormalize(alias_term) => {
|
||||
let alias_term = self.resolve_vars_if_possible(alias_term);
|
||||
let kind = alias_term.kind(self.tcx).descr();
|
||||
let alias_str = with_short_path(self.tcx, alias_term);
|
||||
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);
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
|
||||
| ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0275,
|
||||
"overflow assigning `{a}` to `{b}`",
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
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 {
|
||||
suggest_new_overflow_limit(self.tcx, &mut err);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
/// Reports that an overflow has occurred and halts compilation. We
|
||||
/// halt compilation unconditionally because it is important that
|
||||
/// overflows never be masked -- they basically represent computations
|
||||
/// 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_obligation<T>(
|
||||
&self,
|
||||
obligation: &Obligation<'tcx, T>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> !
|
||||
where
|
||||
T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
|
||||
{
|
||||
let predicate = obligation.predicate.clone().upcast(self.tcx);
|
||||
let predicate = self.resolve_vars_if_possible(predicate);
|
||||
self.report_overflow_error(
|
||||
OverflowCause::TraitSolver(predicate),
|
||||
obligation.cause.span,
|
||||
suggest_increasing_limit,
|
||||
|err| {
|
||||
self.note_obligation_cause_code(
|
||||
obligation.cause.body_id,
|
||||
err,
|
||||
predicate,
|
||||
obligation.param_env,
|
||||
obligation.cause.code(),
|
||||
&mut vec![],
|
||||
&mut Default::default(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Reports that a cycle was detected which led to overflow and halts
|
||||
/// compilation. This is equivalent to `report_overflow_obligation` except
|
||||
/// that we can give a more helpful error message (and, in particular,
|
||||
/// we do not suggest increasing the overflow limit, which is not
|
||||
/// going to help).
|
||||
fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
|
||||
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
|
||||
assert!(!cycle.is_empty());
|
||||
|
||||
debug!(?cycle, "report_overflow_error_cycle");
|
||||
|
||||
// The 'deepest' obligation is most likely to have a useful
|
||||
// cause 'backtrace'
|
||||
self.report_overflow_obligation(
|
||||
cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
fn report_overflow_no_abort(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> ErrorGuaranteed {
|
||||
let obligation = self.resolve_vars_if_possible(obligation);
|
||||
let mut err = self.build_overflow_error(
|
||||
OverflowCause::TraitSolver(obligation.predicate),
|
||||
obligation.cause.span,
|
||||
suggest_increasing_limit,
|
||||
);
|
||||
self.note_obligation_cause(&mut err, &obligation);
|
||||
self.point_at_returns_when_relevant(&mut err, &obligation);
|
||||
err.emit()
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
|
||||
use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
|
||||
use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
|
||||
use crate::error_reporting::traits::overflow::TypeErrCtxtOverflowExt;
|
||||
use crate::error_reporting::traits::to_pretty_impl_header;
|
||||
use crate::error_reporting::traits::{ambiguity, ambiguity::CandidateSource::*};
|
||||
use crate::errors::{
|
||||
|
@ -23,7 +24,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
|||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
|
||||
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir::def::{DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
@ -46,12 +47,9 @@ use rustc_middle::ty::{
|
|||
TypeVisitableExt, Upcast,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
|
||||
use super::{
|
||||
|
@ -61,27 +59,6 @@ use super::{
|
|||
|
||||
pub use rustc_infer::traits::error_reporting::*;
|
||||
|
||||
pub enum OverflowCause<'tcx> {
|
||||
DeeplyNormalize(ty::AliasTerm<'tcx>),
|
||||
TraitSolver(ty::Predicate<'tcx>),
|
||||
}
|
||||
|
||||
pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diag<'_, G>,
|
||||
) {
|
||||
let suggested_limit = match tcx.recursion_limit() {
|
||||
Limit(0) => Limit(2),
|
||||
limit => limit * 2,
|
||||
};
|
||||
err.help(format!(
|
||||
"consider increasing the recursion limit by adding a \
|
||||
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
|
||||
suggested_limit,
|
||||
tcx.crate_name(LOCAL_CRATE),
|
||||
));
|
||||
}
|
||||
|
||||
#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)]
|
||||
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
fn report_fulfillment_errors(
|
||||
|
@ -204,161 +181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
|
||||
}
|
||||
|
||||
/// Reports that an overflow has occurred and halts compilation. We
|
||||
/// halt compilation unconditionally because it is important that
|
||||
/// overflows never be masked -- they basically represent computations
|
||||
/// 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(
|
||||
&self,
|
||||
cause: OverflowCause<'tcx>,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
mutate: impl FnOnce(&mut Diag<'_>),
|
||||
) -> ! {
|
||||
let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
|
||||
mutate(&mut err);
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
fn build_overflow_error(
|
||||
&self,
|
||||
cause: OverflowCause<'tcx>,
|
||||
span: Span,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> Diag<'a> {
|
||||
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 = match cause {
|
||||
OverflowCause::DeeplyNormalize(alias_term) => {
|
||||
let alias_term = self.resolve_vars_if_possible(alias_term);
|
||||
let kind = alias_term.kind(self.tcx).descr();
|
||||
let alias_str = with_short_path(self.tcx, alias_term);
|
||||
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);
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
|
||||
| ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0275,
|
||||
"overflow assigning `{a}` to `{b}`",
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
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 {
|
||||
suggest_new_overflow_limit(self.tcx, &mut err);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
/// Reports that an overflow has occurred and halts compilation. We
|
||||
/// halt compilation unconditionally because it is important that
|
||||
/// overflows never be masked -- they basically represent computations
|
||||
/// 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_obligation<T>(
|
||||
&self,
|
||||
obligation: &Obligation<'tcx, T>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> !
|
||||
where
|
||||
T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
|
||||
{
|
||||
let predicate = obligation.predicate.clone().upcast(self.tcx);
|
||||
let predicate = self.resolve_vars_if_possible(predicate);
|
||||
self.report_overflow_error(
|
||||
OverflowCause::TraitSolver(predicate),
|
||||
obligation.cause.span,
|
||||
suggest_increasing_limit,
|
||||
|err| {
|
||||
self.note_obligation_cause_code(
|
||||
obligation.cause.body_id,
|
||||
err,
|
||||
predicate,
|
||||
obligation.param_env,
|
||||
obligation.cause.code(),
|
||||
&mut vec![],
|
||||
&mut Default::default(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Reports that a cycle was detected which led to overflow and halts
|
||||
/// compilation. This is equivalent to `report_overflow_obligation` except
|
||||
/// that we can give a more helpful error message (and, in particular,
|
||||
/// we do not suggest increasing the overflow limit, which is not
|
||||
/// going to help).
|
||||
fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
|
||||
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
|
||||
assert!(!cycle.is_empty());
|
||||
|
||||
debug!(?cycle, "report_overflow_error_cycle");
|
||||
|
||||
// The 'deepest' obligation is most likely to have a useful
|
||||
// cause 'backtrace'
|
||||
self.report_overflow_obligation(
|
||||
cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
fn report_overflow_no_abort(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> ErrorGuaranteed {
|
||||
let obligation = self.resolve_vars_if_possible(obligation);
|
||||
let mut err = self.build_overflow_error(
|
||||
OverflowCause::TraitSolver(obligation.predicate),
|
||||
obligation.cause.span,
|
||||
suggest_increasing_limit,
|
||||
);
|
||||
self.note_obligation_cause(&mut err, &obligation);
|
||||
self.point_at_returns_when_relevant(&mut err, &obligation);
|
||||
err.emit()
|
||||
}
|
||||
|
||||
/// The `root_obligation` parameter should be the `root_obligation` field
|
||||
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
|
||||
/// then it should be the same as `obligation`.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtExt};
|
||||
use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtOverflowExt};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
|
||||
use crate::infer::{InferCtxt, TyOrConstInferVar};
|
||||
use crate::traits::normalize::normalize_with_depth_to;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use super::SelectionContext;
|
||||
use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
|
||||
use crate::error_reporting::traits::OverflowCause;
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
|
||||
use crate::solve::NextSolverError;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_infer::infer::at::At;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! `normalize_canonicalized_projection_ty` query when it encounters projections.
|
||||
|
||||
use crate::error_reporting::traits::OverflowCause;
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
|
||||
use crate::infer::at::At;
|
||||
use crate::infer::canonical::OriginalQueryValues;
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
|
|
|
@ -18,7 +18,7 @@ use super::{
|
|||
TraitQueryMode,
|
||||
};
|
||||
|
||||
use crate::error_reporting::traits::TypeErrCtxtExt;
|
||||
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
|
||||
use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
|
||||
use crate::solve::InferCtxtSelectExt as _;
|
||||
use crate::traits::normalize::normalize_with_depth;
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt;
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::CodegenObligationError;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
|
||||
use rustc_trait_selection::traits::{
|
||||
ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
|
||||
Unimplemented,
|
||||
|
|
|
@ -2,7 +2,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
|||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
|
||||
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::{
|
||||
normalize::NormalizationResult, CanonicalAliasGoal, NoSolution,
|
||||
|
|
Loading…
Reference in New Issue