about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2018-12-02 18:21:41 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2018-12-15 00:41:28 +0200
commit12c17f91103c125397d4a95212349f226ddba3bd (patch)
treefc13f59894b04e2246602a452945576304f00a55
parente25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1 (diff)
downloadrust-12c17f91103c125397d4a95212349f226ddba3bd.tar.gz
rust-12c17f91103c125397d4a95212349f226ddba3bd.zip
move overflow error reporting out of the query
that allows the error reporting to contain the span.
-rw-r--r--src/librustc/traits/query/method_autoderef.rs7
-rw-r--r--src/librustc_typeck/check/autoderef.rs58
-rw-r--r--src/librustc_typeck/check/method/probe.rs37
3 files changed, 73 insertions, 29 deletions
diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs
index e67497915d7..175883eb2a7 100644
--- a/src/librustc/traits/query/method_autoderef.rs
+++ b/src/librustc/traits/query/method_autoderef.rs
@@ -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> {
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index 3fce66a19d8..d240f45c7d9 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -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)
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 539c33cc14a..29fd9f5f71e 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -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()
         }
     })
 }