about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-09-18 12:05:37 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-09-19 12:10:23 -0700
commitc1ed4399eb3b68a2df0abda9483826f4a0e83046 (patch)
tree909612eaf36ff79ee46c9af606387841cf13cad0
parent2fbd6927a5116e856aa7085bbcab27e87271bb91 (diff)
downloadrust-c1ed4399eb3b68a2df0abda9483826f4a0e83046.tar.gz
rust-c1ed4399eb3b68a2df0abda9483826f4a0e83046.zip
review comments
-rw-r--r--src/librustc/traits/error_reporting.rs4
-rw-r--r--src/librustc/traits/mod.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs42
-rw-r--r--src/librustc_typeck/check/op.rs2
4 files changed, 33 insertions, 18 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index e52451b2fdc..1d87484ef09 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1014,6 +1014,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                         _ => "_".to_string(),
                                     }).collect::<Vec<_>>().join(", "),
                             );
+                            // When the obligation error has been ensured to have been caused by
+                            // an argument, the `obligation.cause.span` points at the expression
+                            // of the argument, so we can provide a suggestion. This is signaled
+                            // by `points_at_arg`. Otherwise, we give a more general note.
                             if points_at_arg {
                                 err.span_suggestion(
                                     obligation.cause.span,
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index b7db7c25206..c53f4e49971 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -485,6 +485,9 @@ EnumTypeFoldableImpl! {
 pub struct FulfillmentError<'tcx> {
     pub obligation: PredicateObligation<'tcx>,
     pub code: FulfillmentErrorCode<'tcx>,
+    /// Diagnostics only: we opportunistically change the `code.span` when we encounter an
+    /// obligation error caused by a call argument. When this is the case, we also signal that in
+    /// this field to ensure accuracy of suggestions.
     pub points_at_arg_span: bool,
 }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index df9955d6ba0..430e57810d9 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -885,12 +885,12 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
         };
 
         // All type checking constraints were added, try to fallback unsolved variables.
-        fcx.select_obligations_where_possible(false);
+        fcx.select_obligations_where_possible(false, |_| {});
         let mut fallback_has_occurred = false;
         for ty in &fcx.unsolved_variables() {
             fallback_has_occurred |= fcx.fallback_if_possible(ty);
         }
-        fcx.select_obligations_where_possible(fallback_has_occurred);
+        fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
 
         // Even though coercion casts provide type hints, we check casts after fallback for
         // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
@@ -2356,7 +2356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // possible. This can help substantially when there are
         // indirect dependencies that don't seem worth tracking
         // precisely.
-        self.select_obligations_where_possible(false);
+        self.select_obligations_where_possible(false, |_| {});
         ty = self.resolve_vars_if_possible(&ty);
 
         debug!("resolve_type_vars_with_obligations: ty={:?}", ty);
@@ -2807,7 +2807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn resolve_generator_interiors(&self, def_id: DefId) {
         let mut generators = self.deferred_generator_interiors.borrow_mut();
         for (body_id, interior, kind) in generators.drain(..) {
-            self.select_obligations_where_possible(false);
+            self.select_obligations_where_possible(false, |_| {});
             generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
         }
     }
@@ -2844,8 +2844,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Select as many obligations as we can at present.
-    fn select_obligations_where_possible(&self, fallback_has_occurred: bool) {
-        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_where_possible(self) {
+    fn select_obligations_where_possible(
+        &self,
+        fallback_has_occurred: bool,
+        f: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
+    ) {
+        if let Err(mut errors) = self.fulfillment_cx.borrow_mut().select_where_possible(self) {
+            f(&mut errors);
             self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
         }
     }
@@ -3267,20 +3272,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // an "opportunistic" vtable resolution of any trait bounds on
             // the call. This helps coercions.
             if check_closures {
-                // We don't use `select_obligations_where_possible` to try to figure out if the
-                // obligation is comming from a single fn call argument, and if it is, we point
-                // at the expression corresponding to that argument, instead of the call.
-                if let Err(
-                    mut errors,
-                ) = self.fulfillment_cx.borrow_mut().select_where_possible(self) {
+                self.select_obligations_where_possible(false, |errors| {
                     self.point_at_arg_instead_of_call_if_possible(
-                        &mut errors,
+                        errors,
                         &final_arg_types[..],
                         sp,
                         &args,
                     );
-                    self.report_fulfillment_errors(&errors, self.inh.body_id, false);
-                }
+                })
             }
 
             // For C-variadic functions, we don't have a declared type for all of
@@ -3394,8 +3393,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             }
                         }
                     }
-                    if referenced_in.len() == 1 {
-                        error.obligation.cause.span = args[referenced_in[0]].span;
+                    let mut referenced_in = final_arg_types.iter()
+                        .flat_map(|(i, ty)| {
+                            let ty = self.resolve_vars_if_possible(ty);
+                            ty.walk()
+                                .filter(|&ty| ty == predicate.skip_binder().self_ty())
+                                .map(move |_| *i)
+                        });
+                    if let (Some(ref_in), None) = (referenced_in.next(), referenced_in.next()) {
+                        // We make sure that only *one* argument matches the obligation failure
+                        // and thet the obligation's span to its expression's.
+                        error.obligation.cause.span = args[ref_in].span;
                         error.points_at_arg_span = true;
                     }
                 }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 18b555dc037..956d04ff622 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -724,7 +724,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match method {
             Some(ok) => {
                 let method = self.register_infer_ok_obligations(ok);
-                self.select_obligations_where_possible(false);
+                self.select_obligations_where_possible(false, |_| {});
 
                 Ok(method)
             }