about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYukio Siraichi <yukio.siraichi@gmail.com>2018-02-09 19:04:12 +0100
committerYukio Siraichi <yukio.siraichi@gmail.com>2018-03-17 15:53:33 -0300
commitfab7020bd95c695be4f3c06dce236fada0dabb8e (patch)
tree50718df5dcf4503c34452be9a1d4d1f1999f2830
parent61b6bf54fdf56195baf9a8ee7383551b0d468c81 (diff)
downloadrust-fab7020bd95c695be4f3c06dce236fada0dabb8e.tar.gz
rust-fab7020bd95c695be4f3c06dce236fada0dabb8e.zip
Add span_suggestion while removing TyRefs based on the snippet String.
-rw-r--r--src/librustc/traits/error_reporting.rs87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 7e5dc02798d..c90a6d0709d 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -575,6 +575,44 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             = self.on_unimplemented_note(trait_ref, obligation);
                         let have_alt_message = message.is_some() || label.is_some();
 
+                        // {
+                        //     let ty::Binder(trait_ref) = trait_ref;
+                        //     println!("TraitRef: {:?}", trait_ref);
+                        //     println!("TraitRef: id:{:?}; subst:{:?}", trait_ref.def_id, trait_ref.substs);
+
+                        //     if let ty::Predicate::Trait(trait_predicate_binder) =
+                        //         trait_ref.to_predicate() {
+                        //             let trait_predicate = trait_predicate_binder.skip_binder();
+                        //             println!("TraitPredicateBinder: {:?}", trait_predicate_binder);
+                        //             println!("TraitPredicate: {:?}", trait_predicate);
+
+                        //             let trait_ty = trait_ref.self_ty();
+                        //             println!("TraitPredicateTy: {:?}", trait_ty);
+                        //             println!("TraitPredicateTy: sty:{:?}; flags{:?}", trait_ty.sty, trait_ty.flags);
+                        //         }
+
+                        //     for in_ty in trait_ref.input_types() {
+                        //         println!("\t- {:?}", in_ty);
+                        //         println!("\t\t- sty:{:?}; flags:{:?}", in_ty.sty, in_ty.flags);
+                        //     }
+
+                        //     println!("Message: {:?}", message);
+                        //     println!("Label: {:?}", label);
+                        //     println!("Obligation: {:?}", obligation);
+                        //     println!("Span: {:?}", self.tcx.sess.codemap().span_to_string(span));
+
+                        //     let body_id = obligation.cause.body_id;
+                        //     println!("BodyId: {:?}", body_id);
+                        //     println!("BodyIdSpan: {:?}", self.tcx.hir.span(body_id));
+
+                        //     match self.tcx.hir.find(body_id) {
+                        //         Some(node) => println!("Node: {:?}", node),
+                        //         None => println!("Node not found."),
+                        //     }
+
+                        //     println!("=------------------------------=");
+                        // }
+
                         let mut err = struct_span_err!(
                             self.tcx.sess,
                             span,
@@ -606,6 +644,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         }
 
                         self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
+                        self.suggest_remove_reference(&obligation, &mut err, &trait_ref);
 
                         // Try to report a help message
                         if !trait_ref.has_infer_types() &&
@@ -844,6 +883,54 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    fn suggest_remove_reference(&self,
+                                obligation: &PredicateObligation<'tcx>,
+                                err: &mut DiagnosticBuilder<'tcx>,
+                                trait_ref: &ty::Binder<ty::TraitRef<'tcx>>) {
+        let ty::Binder(trait_ref) = trait_ref;
+
+        let span = obligation.cause.span;
+        let mut snippet = match self.tcx.sess.codemap().span_to_snippet(span) {
+            Ok(s) => s,
+            Err(_) => String::from(""),
+        };
+
+        let mut refs_number = 0;
+
+        for c in snippet.chars() {
+            if c == '&' {
+                refs_number += 1;
+            }
+        }
+
+        let mut refs_remaining = refs_number;
+        let mut trait_type = trait_ref.self_ty();
+        let mut selcx = SelectionContext::new(self);
+
+        while refs_remaining > 0 {
+            if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) =
+                trait_type.sty {
+                    trait_type = t_type;
+                    refs_remaining -= 1;
+
+                    let substs = self.tcx.mk_substs_trait(trait_type, &[]);
+                    let new_trait_ref = ty::TraitRef::new(trait_ref.def_id, substs);
+                    let new_obligation = Obligation::new(ObligationCause::dummy(),
+                                                         obligation.param_env,
+                                                         new_trait_ref.to_predicate());
+
+                    if selcx.evaluate_obligation(&new_obligation) {
+                        for i in 0..refs_number {
+                            snippet.remove(i);
+                        }
+                        err.span_suggestion(span, "consider removing `&`s like", format!("{}", snippet));
+                    }
+                } else {
+                    break;
+                }
+        }
+    }
+
     /// Given some node representing a fn-like thing in the HIR map,
     /// returns a span and `ArgKind` information that describes the
     /// arguments it expects. This can be supplied to