move overflow error reporting out of the query

that allows the error reporting to contain the span.
This commit is contained in:
Ariel Ben-Yehuda 2018-12-02 18:21:41 +02:00
parent e25e2e0600
commit 12c17f9110
3 changed files with 73 additions and 29 deletions

View file

@ -30,7 +30,10 @@ pub struct MethodAutoderefStepsResult<'tcx> {
/// The valid autoderef steps that could be find.
pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
/// If Some(T), a type autoderef reported an error on.
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
/// If `true`, `steps` has been truncated due to reaching the
/// recursion limit.
pub reached_recursion_limit: bool,
}
#[derive(Debug)]
@ -44,7 +47,7 @@ impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
});
impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
steps, opt_bad_ty
reached_recursion_limit, steps, opt_bad_ty
});
impl_stable_hash_for!(struct CandidateStep<'tcx> {

View file

@ -14,7 +14,7 @@ use super::method::MethodCallee;
use rustc::infer::{InferCtxt, InferOk};
use rustc::session::DiagnosticMessageId;
use rustc::traits::{self, TraitEngine};
use rustc::ty::{self, Ty, TraitRef};
use rustc::ty::{self, Ty, TyCtxt, TraitRef};
use rustc::ty::{ToPredicate, TypeFoldable};
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
@ -39,6 +39,8 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
at_start: bool,
include_raw_pointers: bool,
span: Span,
silence_errors: bool,
reached_recursion_limit: bool
}
impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
@ -57,24 +59,10 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
}
if self.steps.len() >= *tcx.sess.recursion_limit.get() {
// We've reached the recursion limit, error gracefully.
let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
self.cur_ty);
let error_id = (DiagnosticMessageId::ErrorId(55), Some(self.span), msg);
let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
if fresh {
struct_span_err!(tcx.sess,
self.span,
E0055,
"reached the recursion limit while auto-dereferencing `{:?}`",
self.cur_ty)
.span_label(self.span, "deref recursion limit reached")
.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit))
.emit();
if !self.silence_errors {
report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
}
self.reached_recursion_limit = true;
return None;
}
@ -123,6 +111,8 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
obligations: vec![],
at_start: true,
include_raw_pointers: false,
silence_errors: false,
reached_recursion_limit: false,
span,
}
}
@ -240,6 +230,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
self
}
pub fn silence_errors(mut self) -> Self {
self.silence_errors = true;
self
}
pub fn reached_recursion_limit(&self) -> bool {
self.reached_recursion_limit
}
pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
fcx.register_predicates(self.into_obligations());
}
@ -249,6 +248,29 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
}
}
pub fn report_autoderef_recursion_limit_error<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>, span: Span, ty: Ty<'tcx>)
{
// We've reached the recursion limit, error gracefully.
let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
ty);
let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
if fresh {
struct_span_err!(tcx.sess,
span,
E0055,
"reached the recursion limit while auto-dereferencing `{:?}`",
ty)
.span_label(span, "deref recursion limit reached")
.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit))
.emit();
}
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
Autoderef::new(self, self.param_env, self.body_id, span, base_ty)

View file

@ -13,7 +13,7 @@ use super::NoMatchData;
use super::{CandidateSource, ImplSource, TraitSource};
use super::suggest;
use check::autoderef::Autoderef;
use check::autoderef::{self, Autoderef};
use check::FnCtxt;
use hir::def_id::DefId;
use hir::def::Def;
@ -283,19 +283,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
from_unsafe_deref: false,
unsize: false,
}]),
opt_bad_ty: None
opt_bad_ty: None,
reached_recursion_limit: false
}
})
};
// If our autoderef loop had reached the recursion limit,
// report an overflow error, but continue going on with
// the truncated autoderef list.
if steps.reached_recursion_limit {
self.probe(|_| {
let ty = &steps.steps.last().unwrap_or_else(|| {
span_bug!(span, "reached the recursion limit in 0 steps?")
}).self_ty;
let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
autoderef::report_autoderef_recursion_limit_error(self.tcx, span,
ty.value);
});
}
// If we encountered an `_` type or an error type during autoderef, this is
// ambiguous.
if let Some(autoderef_bad_ty) = &steps.opt_bad_ty {
let MethodAutoderefBadTy { reached_raw_pointer, ref ty } = **autoderef_bad_ty;
if let Some(bad_ty) = &steps.opt_bad_ty {
if is_suggestion.0 {
// Ambiguity was encountered during a suggestion. Just keep going.
debug!("ProbeContext: encountered ambiguity in suggestion");
} else if reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
} else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
// this case used to be allowed by the compiler,
// so we do a future-compat lint here for the 2015 edition
// (see https://github.com/rust-lang/rust/issues/46906)
@ -314,10 +330,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Encountered a real ambiguity, so abort the lookup. If `ty` is not
// an `Err`, report the right "type annotations needed" error pointing
// to it.
let ty = &bad_ty.ty;
let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
let t = self.structurally_resolved_type(span, ty.value);
assert_eq!(t, self.tcx.types.err);
let ty = self.structurally_resolved_type(span, ty.value);
assert_eq!(ty, self.tcx.types.err);
return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
Vec::new(),
Vec::new(),
@ -365,7 +382,8 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
let ParamEnvAnd { param_env, value: self_ty } = goal;
let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty)
.include_raw_pointers();
.include_raw_pointers()
.silence_errors();
let mut reached_raw_pointer = false;
let mut steps: Vec<_> = autoderef.by_ref()
.map(|(ty, d)| {
@ -416,7 +434,8 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
MethodAutoderefStepsResult {
steps: Lrc::new(steps),
opt_bad_ty: opt_bad_ty.map(Lrc::new)
opt_bad_ty: opt_bad_ty.map(Lrc::new),
reached_recursion_limit: autoderef.reached_recursion_limit()
}
})
}