Skip to content

Commit 12c17f9

Browse files
committed
move overflow error reporting out of the query
that allows the error reporting to contain the span.
1 parent e25e2e0 commit 12c17f9

File tree

3 files changed

+73
-29
lines changed

3 files changed

+73
-29
lines changed

src/librustc/traits/query/method_autoderef.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ pub struct MethodAutoderefStepsResult<'tcx> {
3030
/// The valid autoderef steps that could be find.
3131
pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
3232
/// If Some(T), a type autoderef reported an error on.
33-
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>
33+
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
34+
/// If `true`, `steps` has been truncated due to reaching the
35+
/// recursion limit.
36+
pub reached_recursion_limit: bool,
3437
}
3538

3639
#[derive(Debug)]
@@ -44,7 +47,7 @@ impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
4447
});
4548

4649
impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
47-
steps, opt_bad_ty
50+
reached_recursion_limit, steps, opt_bad_ty
4851
});
4952

5053
impl_stable_hash_for!(struct CandidateStep<'tcx> {

src/librustc_typeck/check/autoderef.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use super::method::MethodCallee;
1414
use rustc::infer::{InferCtxt, InferOk};
1515
use rustc::session::DiagnosticMessageId;
1616
use rustc::traits::{self, TraitEngine};
17-
use rustc::ty::{self, Ty, TraitRef};
17+
use rustc::ty::{self, Ty, TyCtxt, TraitRef};
1818
use rustc::ty::{ToPredicate, TypeFoldable};
1919
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
2020

@@ -39,6 +39,8 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
3939
at_start: bool,
4040
include_raw_pointers: bool,
4141
span: Span,
42+
silence_errors: bool,
43+
reached_recursion_limit: bool
4244
}
4345

4446
impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
@@ -57,24 +59,10 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
5759
}
5860

5961
if self.steps.len() >= *tcx.sess.recursion_limit.get() {
60-
// We've reached the recursion limit, error gracefully.
61-
let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
62-
let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
63-
self.cur_ty);
64-
let error_id = (DiagnosticMessageId::ErrorId(55), Some(self.span), msg);
65-
let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
66-
if fresh {
67-
struct_span_err!(tcx.sess,
68-
self.span,
69-
E0055,
70-
"reached the recursion limit while auto-dereferencing `{:?}`",
71-
self.cur_ty)
72-
.span_label(self.span, "deref recursion limit reached")
73-
.help(&format!(
74-
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
75-
suggested_limit))
76-
.emit();
62+
if !self.silence_errors {
63+
report_autoderef_recursion_limit_error(tcx, self.span, self.cur_ty);
7764
}
65+
self.reached_recursion_limit = true;
7866
return None;
7967
}
8068

@@ -123,6 +111,8 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
123111
obligations: vec![],
124112
at_start: true,
125113
include_raw_pointers: false,
114+
silence_errors: false,
115+
reached_recursion_limit: false,
126116
span,
127117
}
128118
}
@@ -240,6 +230,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
240230
self
241231
}
242232

233+
pub fn silence_errors(mut self) -> Self {
234+
self.silence_errors = true;
235+
self
236+
}
237+
238+
pub fn reached_recursion_limit(&self) -> bool {
239+
self.reached_recursion_limit
240+
}
241+
243242
pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
244243
fcx.register_predicates(self.into_obligations());
245244
}
@@ -249,6 +248,29 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
249248
}
250249
}
251250

251+
pub fn report_autoderef_recursion_limit_error<'a, 'gcx, 'tcx>(
252+
tcx: TyCtxt<'a, 'gcx, 'tcx>, span: Span, ty: Ty<'tcx>)
253+
{
254+
// We've reached the recursion limit, error gracefully.
255+
let suggested_limit = *tcx.sess.recursion_limit.get() * 2;
256+
let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`",
257+
ty);
258+
let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg);
259+
let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id);
260+
if fresh {
261+
struct_span_err!(tcx.sess,
262+
span,
263+
E0055,
264+
"reached the recursion limit while auto-dereferencing `{:?}`",
265+
ty)
266+
.span_label(span, "deref recursion limit reached")
267+
.help(&format!(
268+
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
269+
suggested_limit))
270+
.emit();
271+
}
272+
}
273+
252274
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
253275
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
254276
Autoderef::new(self, self.param_env, self.body_id, span, base_ty)

src/librustc_typeck/check/method/probe.rs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use super::NoMatchData;
1313
use super::{CandidateSource, ImplSource, TraitSource};
1414
use super::suggest;
1515

16-
use check::autoderef::Autoderef;
16+
use check::autoderef::{self, Autoderef};
1717
use check::FnCtxt;
1818
use hir::def_id::DefId;
1919
use hir::def::Def;
@@ -283,19 +283,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
283283
from_unsafe_deref: false,
284284
unsize: false,
285285
}]),
286-
opt_bad_ty: None
286+
opt_bad_ty: None,
287+
reached_recursion_limit: false
287288
}
288289
})
289290
};
290291

292+
// If our autoderef loop had reached the recursion limit,
293+
// report an overflow error, but continue going on with
294+
// the truncated autoderef list.
295+
if steps.reached_recursion_limit {
296+
self.probe(|_| {
297+
let ty = &steps.steps.last().unwrap_or_else(|| {
298+
span_bug!(span, "reached the recursion limit in 0 steps?")
299+
}).self_ty;
300+
let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
301+
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
302+
autoderef::report_autoderef_recursion_limit_error(self.tcx, span,
303+
ty.value);
304+
});
305+
}
306+
307+
291308
// If we encountered an `_` type or an error type during autoderef, this is
292309
// ambiguous.
293-
if let Some(autoderef_bad_ty) = &steps.opt_bad_ty {
294-
let MethodAutoderefBadTy { reached_raw_pointer, ref ty } = **autoderef_bad_ty;
310+
if let Some(bad_ty) = &steps.opt_bad_ty {
295311
if is_suggestion.0 {
296312
// Ambiguity was encountered during a suggestion. Just keep going.
297313
debug!("ProbeContext: encountered ambiguity in suggestion");
298-
} else if reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
314+
} else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
299315
// this case used to be allowed by the compiler,
300316
// so we do a future-compat lint here for the 2015 edition
301317
// (see https://github.com/rust-lang/rust/issues/46906)
@@ -314,10 +330,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
314330
// Encountered a real ambiguity, so abort the lookup. If `ty` is not
315331
// an `Err`, report the right "type annotations needed" error pointing
316332
// to it.
333+
let ty = &bad_ty.ty;
317334
let ty = self.probe_instantiate_query_response(span, &orig_values, ty)
318335
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
319-
let t = self.structurally_resolved_type(span, ty.value);
320-
assert_eq!(t, self.tcx.types.err);
336+
let ty = self.structurally_resolved_type(span, ty.value);
337+
assert_eq!(ty, self.tcx.types.err);
321338
return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(),
322339
Vec::new(),
323340
Vec::new(),
@@ -365,7 +382,8 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
365382
let ParamEnvAnd { param_env, value: self_ty } = goal;
366383

367384
let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty)
368-
.include_raw_pointers();
385+
.include_raw_pointers()
386+
.silence_errors();
369387
let mut reached_raw_pointer = false;
370388
let mut steps: Vec<_> = autoderef.by_ref()
371389
.map(|(ty, d)| {
@@ -416,7 +434,8 @@ fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
416434

417435
MethodAutoderefStepsResult {
418436
steps: Lrc::new(steps),
419-
opt_bad_ty: opt_bad_ty.map(Lrc::new)
437+
opt_bad_ty: opt_bad_ty.map(Lrc::new),
438+
reached_recursion_limit: autoderef.reached_recursion_limit()
420439
}
421440
})
422441
}

0 commit comments

Comments
 (0)