move overflow error reporting out of the query
that allows the error reporting to contain the span.
This commit is contained in:
parent
e25e2e0600
commit
12c17f9110
3 changed files with 73 additions and 29 deletions
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue