mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Fix ice when error reporting recursion errors
Fixes: #90319, #92148, #93955
This commit is contained in:
parent
37b55c8a0c
commit
85e67b9a59
@ -478,7 +478,7 @@ pub enum SelectionError<'tcx> {
|
||||
/// A given constant couldn't be evaluated.
|
||||
NotConstEvaluatable(NotConstEvaluatable),
|
||||
/// Exceeded the recursion depth during type projection.
|
||||
Overflow,
|
||||
Overflow(OverflowError),
|
||||
/// Signaling that an error has already been emitted, to avoid
|
||||
/// multiple errors being shown.
|
||||
ErrorReporting,
|
||||
|
@ -5,6 +5,7 @@
|
||||
use self::EvaluationResult::*;
|
||||
|
||||
use super::{SelectionError, SelectionResult};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
||||
use crate::ty;
|
||||
|
||||
@ -264,14 +265,26 @@ impl EvaluationResult {
|
||||
/// Indicates that trait evaluation caused overflow and in which pass.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
|
||||
pub enum OverflowError {
|
||||
Error(ErrorGuaranteed),
|
||||
Canonical,
|
||||
ErrorReporting,
|
||||
}
|
||||
|
||||
impl From<ErrorGuaranteed> for OverflowError {
|
||||
fn from(e: ErrorGuaranteed) -> OverflowError {
|
||||
OverflowError::Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeFoldableAndLiftImpls! {
|
||||
OverflowError,
|
||||
}
|
||||
|
||||
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
|
||||
match overflow_error {
|
||||
OverflowError::Canonical => SelectionError::Overflow,
|
||||
OverflowError::Error(e) => SelectionError::Overflow(OverflowError::Error(e)),
|
||||
OverflowError::Canonical => SelectionError::Overflow(OverflowError::Canonical),
|
||||
OverflowError::ErrorReporting => SelectionError::ErrorReporting,
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use rustc_hir::GenericParam;
|
||||
use rustc_hir::Item;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::fold::TypeFolder;
|
||||
use rustc_middle::ty::{
|
||||
@ -928,8 +929,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error");
|
||||
return;
|
||||
}
|
||||
|
||||
Overflow => {
|
||||
// Already reported.
|
||||
Overflow(OverflowError::Error(_)) => {
|
||||
self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported");
|
||||
return;
|
||||
}
|
||||
Overflow(_) => {
|
||||
bug!("overflow should be handled before the `report_selection_error` path");
|
||||
}
|
||||
SelectionError::ErrorReporting => {
|
||||
|
@ -27,6 +27,7 @@ use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_middle::traits::select::OverflowError;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
|
||||
@ -1139,7 +1140,9 @@ fn project<'cx, 'tcx>(
|
||||
if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) {
|
||||
// This should really be an immediate error, but some existing code
|
||||
// relies on being able to recover from this.
|
||||
return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow));
|
||||
return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow(
|
||||
OverflowError::Canonical,
|
||||
)));
|
||||
}
|
||||
|
||||
if obligation.predicate.references_error() {
|
||||
|
@ -108,9 +108,11 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
)
|
||||
}
|
||||
OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr,
|
||||
OverflowError::Error(_) => EvaluationResult::EvaluatedToErr,
|
||||
})
|
||||
}
|
||||
Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr,
|
||||
Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,8 +164,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
|
||||
}
|
||||
Ok(_) => Ok(None),
|
||||
Err(OverflowError::Canonical) => Err(Overflow),
|
||||
Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
|
||||
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
|
||||
Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
|
||||
})
|
||||
.flat_map(Result::transpose)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
@ -29,7 +29,7 @@ use crate::traits::project::ProjectionCacheKeyExt;
|
||||
use crate::traits::ProjectionCacheKey;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_errors::{Diagnostic, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
@ -320,11 +320,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||
let candidate = match self.select_from_obligation(obligation) {
|
||||
Err(SelectionError::Overflow) => {
|
||||
Err(SelectionError::Overflow(OverflowError::Canonical)) => {
|
||||
// In standard mode, overflow must have been caught and reported
|
||||
// earlier.
|
||||
assert!(self.query_mode == TraitQueryMode::Canonical);
|
||||
return Err(SelectionError::Overflow);
|
||||
return Err(SelectionError::Overflow(OverflowError::Canonical));
|
||||
}
|
||||
Err(SelectionError::Ambiguous(_)) => {
|
||||
return Ok(None);
|
||||
@ -339,9 +339,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
};
|
||||
|
||||
match self.confirm_candidate(obligation, candidate) {
|
||||
Err(SelectionError::Overflow) => {
|
||||
Err(SelectionError::Overflow(OverflowError::Canonical)) => {
|
||||
assert!(self.query_mode == TraitQueryMode::Canonical);
|
||||
Err(SelectionError::Overflow)
|
||||
Err(SelectionError::Overflow(OverflowError::Canonical))
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
Ok(candidate) => {
|
||||
@ -958,7 +958,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
|
||||
Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
|
||||
Ok(None) => Ok(EvaluatedToAmbig),
|
||||
Err(Overflow) => Err(OverflowError::Canonical),
|
||||
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
|
||||
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
|
||||
Err(..) => Ok(EvaluatedToErr),
|
||||
}
|
||||
@ -1117,7 +1117,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
match self.query_mode {
|
||||
TraitQueryMode::Standard => {
|
||||
if self.infcx.is_tainted_by_errors() {
|
||||
return Err(OverflowError::ErrorReporting);
|
||||
return Err(OverflowError::Error(
|
||||
ErrorGuaranteed::unchecked_claim_error_was_emitted(),
|
||||
));
|
||||
}
|
||||
self.infcx.report_overflow_error(error_obligation, true);
|
||||
}
|
||||
@ -1353,7 +1355,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
if self.can_use_global_caches(param_env) {
|
||||
if let Err(Overflow) = candidate {
|
||||
if let Err(Overflow(OverflowError::Canonical)) = candidate {
|
||||
// Don't cache overflow globally; we only produce this in certain modes.
|
||||
} else if !pred.needs_infer() {
|
||||
if !candidate.needs_infer() {
|
||||
|
17
src/test/ui/typeck/issue-90319.rs
Normal file
17
src/test/ui/typeck/issue-90319.rs
Normal file
@ -0,0 +1,17 @@
|
||||
struct Wrapper<T>(T);
|
||||
|
||||
trait Trait {
|
||||
fn method(&self) {}
|
||||
}
|
||||
|
||||
impl<'a, T> Trait for Wrapper<&'a T> where Wrapper<T>: Trait {}
|
||||
|
||||
fn get<T>() -> T {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let thing = get::<Thing>();//~ERROR cannot find type `Thing` in this scope [E0412]
|
||||
let wrapper = Wrapper(thing);
|
||||
Trait::method(&wrapper);
|
||||
}
|
9
src/test/ui/typeck/issue-90319.stderr
Normal file
9
src/test/ui/typeck/issue-90319.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0412]: cannot find type `Thing` in this scope
|
||||
--> $DIR/issue-90319.rs:14:23
|
||||
|
|
||||
LL | let thing = get::<Thing>();
|
||||
| ^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
Loading…
Reference in New Issue
Block a user