Auto merge of #89576 - tom7980:issue-89275-fix, r=estebank
Prevent error reporting from outputting a recursion error if it finds an ambiguous trait impl during suggestions Closes #89275 This fixes the compiler reporting a recursion error during another already in progress error by trying to make a conversion method suggestion and encounters ambiguous trait implementations that can convert a the original type into a type that can then be recursively converted into itself via another method in the trait. Updated OverflowError struct to be an enum so I could differentiate between passes - it's no longer a ZST but I don't think that should be a problem as they only generate when there's an error in compiling code anyway
This commit is contained in:
commit
e0aaffd8a4
10 changed files with 82 additions and 18 deletions
|
@ -449,6 +449,7 @@ pub enum SelectionError<'tcx> {
|
||||||
TraitNotObjectSafe(DefId),
|
TraitNotObjectSafe(DefId),
|
||||||
NotConstEvaluatable(NotConstEvaluatable),
|
NotConstEvaluatable(NotConstEvaluatable),
|
||||||
Overflow,
|
Overflow,
|
||||||
|
ErrorReporting,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When performing resolution, it is typically the case that there
|
/// When performing resolution, it is typically the case that there
|
||||||
|
|
|
@ -261,12 +261,18 @@ impl EvaluationResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicates that trait evaluation caused overflow.
|
/// Indicates that trait evaluation caused overflow and in which pass.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
|
||||||
pub struct OverflowError;
|
pub enum OverflowError {
|
||||||
|
Cannonical,
|
||||||
|
ErrorReporting,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||||
fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
|
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
|
||||||
SelectionError::Overflow
|
match overflow_error {
|
||||||
|
OverflowError::Cannonical => SelectionError::Overflow,
|
||||||
|
OverflowError::ErrorReporting => SelectionError::ErrorReporting,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -842,6 +842,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
Overflow => {
|
Overflow => {
|
||||||
bug!("overflow should be handled before the `report_selection_error` path");
|
bug!("overflow should be handled before the `report_selection_error` path");
|
||||||
}
|
}
|
||||||
|
SelectionError::ErrorReporting => {
|
||||||
|
bug!("ErrorReporting Overflow should not reach `report_selection_err` call")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.note_obligation_cause(&mut err, &obligation);
|
self.note_obligation_cause(&mut err, &obligation);
|
||||||
|
|
|
@ -83,17 +83,21 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||||
) -> EvaluationResult {
|
) -> EvaluationResult {
|
||||||
match self.evaluate_obligation(obligation) {
|
match self.evaluate_obligation(obligation) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(OverflowError) => {
|
Err(OverflowError::Cannonical) => {
|
||||||
let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
|
let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
|
||||||
selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| {
|
selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
|
||||||
|
OverflowError::Cannonical => {
|
||||||
span_bug!(
|
span_bug!(
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
"Overflow should be caught earlier in standard query mode: {:?}, {:?}",
|
"Overflow should be caught earlier in standard query mode: {:?}, {:?}",
|
||||||
obligation,
|
obligation,
|
||||||
r,
|
r,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::traits;
|
||||||
use crate::traits::coherence::Conflict;
|
use crate::traits::coherence::Conflict;
|
||||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use crate::traits::{util, SelectionResult};
|
use crate::traits::{util, SelectionResult};
|
||||||
use crate::traits::{Overflow, Unimplemented};
|
use crate::traits::{ErrorReporting, Overflow, Unimplemented};
|
||||||
|
|
||||||
use super::BuiltinImplConditions;
|
use super::BuiltinImplConditions;
|
||||||
use super::IntercrateAmbiguityCause;
|
use super::IntercrateAmbiguityCause;
|
||||||
|
@ -161,7 +161,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
|
Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
|
||||||
}
|
}
|
||||||
Ok(_) => Ok(None),
|
Ok(_) => Ok(None),
|
||||||
Err(OverflowError) => Err(Overflow),
|
Err(OverflowError::Cannonical) => Err(Overflow),
|
||||||
|
Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
|
||||||
})
|
})
|
||||||
.flat_map(Result::transpose)
|
.flat_map(Result::transpose)
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
|
@ -20,8 +20,8 @@ use super::ObligationCauseCode;
|
||||||
use super::Selection;
|
use super::Selection;
|
||||||
use super::SelectionResult;
|
use super::SelectionResult;
|
||||||
use super::TraitQueryMode;
|
use super::TraitQueryMode;
|
||||||
|
use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
|
||||||
use super::{ObligationCause, PredicateObligation, TraitObligation};
|
use super::{ObligationCause, PredicateObligation, TraitObligation};
|
||||||
use super::{Overflow, SelectionError, Unimplemented};
|
|
||||||
|
|
||||||
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||||
use crate::traits::error_reporting::InferCtxtExt;
|
use crate::traits::error_reporting::InferCtxtExt;
|
||||||
|
@ -900,7 +900,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
match self.candidate_from_obligation(stack) {
|
match self.candidate_from_obligation(stack) {
|
||||||
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
|
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
|
||||||
Ok(None) => Ok(EvaluatedToAmbig),
|
Ok(None) => Ok(EvaluatedToAmbig),
|
||||||
Err(Overflow) => Err(OverflowError),
|
Err(Overflow) => Err(OverflowError::Cannonical),
|
||||||
|
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
|
||||||
Err(..) => Ok(EvaluatedToErr),
|
Err(..) => Ok(EvaluatedToErr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1057,10 +1058,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
|
if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
|
||||||
match self.query_mode {
|
match self.query_mode {
|
||||||
TraitQueryMode::Standard => {
|
TraitQueryMode::Standard => {
|
||||||
|
if self.infcx.is_tainted_by_errors() {
|
||||||
|
return Err(OverflowError::ErrorReporting);
|
||||||
|
}
|
||||||
self.infcx.report_overflow_error(error_obligation, true);
|
self.infcx.report_overflow_error(error_obligation, true);
|
||||||
}
|
}
|
||||||
TraitQueryMode::Canonical => {
|
TraitQueryMode::Canonical => {
|
||||||
return Err(OverflowError);
|
return Err(OverflowError::Cannonical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,6 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Err(e) => e,
|
Err(e) => e,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.set_tainted_by_errors();
|
||||||
let expr = expr.peel_drop_temps();
|
let expr = expr.peel_drop_temps();
|
||||||
let cause = self.misc(expr.span);
|
let cause = self.misc(expr.span);
|
||||||
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
|
let expr_ty = self.resolve_vars_with_obligations(checked_ty);
|
||||||
|
|
|
@ -78,7 +78,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
match infcx.evaluate_obligation(&obligation) {
|
match infcx.evaluate_obligation(&obligation) {
|
||||||
Ok(eval_result) if eval_result.may_apply() => {}
|
Ok(eval_result) if eval_result.may_apply() => {}
|
||||||
Err(traits::OverflowError) => {}
|
Err(traits::OverflowError::Cannonical) => {}
|
||||||
|
Err(traits::OverflowError::ErrorReporting) => {}
|
||||||
_ => {
|
_ => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
29
src/test/ui/typeck/issue-89275.rs
Normal file
29
src/test/ui/typeck/issue-89275.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#![recursion_limit = "5"] // To reduce noise
|
||||||
|
|
||||||
|
//expect mutability error when ambiguous traits are in scope
|
||||||
|
//and not an overflow error on the span in the main function.
|
||||||
|
|
||||||
|
struct Ratio<T>(T);
|
||||||
|
|
||||||
|
pub trait Pow {
|
||||||
|
fn pow(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Pow for &'a Ratio<T>
|
||||||
|
where
|
||||||
|
&'a T: Pow,
|
||||||
|
{
|
||||||
|
fn pow(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downcast<'a, W: ?Sized>() -> &'a W {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Other;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let other: &mut Other = downcast();//~ERROR 28:29: 28:39: mismatched types [E0308]
|
||||||
|
}
|
14
src/test/ui/typeck/issue-89275.stderr
Normal file
14
src/test/ui/typeck/issue-89275.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-89275.rs:28:29
|
||||||
|
|
|
||||||
|
LL | let other: &mut Other = downcast();
|
||||||
|
| ---------- ^^^^^^^^^^ types differ in mutability
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected mutable reference `&mut Other`
|
||||||
|
found reference `&_`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue