about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJanusz Marcinkiewicz <virrages@gmail.com>2019-12-01 13:39:01 +0100
committerJanusz Marcinkiewicz <virrages@gmail.com>2019-12-06 16:59:35 +0100
commitd419a5fdaebb36dbf3c600f624c964d9ea651661 (patch)
tree1ef0c83e647f8a004537e4cddb9439ee22ed0e0d
parentd0126e8ed3cc0d6fcb9dd44c36a46f9ce65010a0 (diff)
downloadrust-d419a5fdaebb36dbf3c600f624c964d9ea651661.tar.gz
rust-d419a5fdaebb36dbf3c600f624c964d9ea651661.zip
Fix pointing at arg when cause is outside of call
-rw-r--r--src/librustc_typeck/check/mod.rs65
-rw-r--r--src/test/ui/issues/issue-66923.rs13
-rw-r--r--src/test/ui/issues/issue-66923.stderr19
3 files changed, 69 insertions, 28 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index c7a0190a1d1..5e644df99be 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3880,36 +3880,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         call_sp: Span,
         args: &'tcx [hir::Expr],
     ) {
-        if !call_sp.desugaring_kind().is_some() {
-            // We *do not* do this for desugared call spans to keep good diagnostics when involving
-            // the `?` operator.
-            for error in errors {
-                if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
-                    // Collect the argument position for all arguments that could have caused this
-                    // `FulfillmentError`.
-                    let mut referenced_in = final_arg_types.iter()
-                        .map(|(i, checked_ty, _)| (i, checked_ty))
-                        .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty)))
-                        .flat_map(|(i, ty)| {
-                            let ty = self.resolve_vars_if_possible(ty);
-                            // We walk the argument type because the argument's type could have
-                            // been `Option<T>`, but the `FulfillmentError` references `T`.
-                            ty.walk()
-                                .filter(|&ty| ty == predicate.skip_binder().self_ty())
-                                .map(move |_| *i)
-                        })
-                        .collect::<Vec<_>>();
+        // We *do not* do this for desugared call spans to keep good diagnostics when involving
+        // the `?` operator.
+        if call_sp.desugaring_kind().is_some() {
+            return
+        }
+
+        for error in errors {
+            // Only if the cause is somewhere inside the expression we want try to point at arg.
+            // Otherwise, it means that the cause is somewhere else and we should not change
+            // anything because we can break the correct span.
+            if !call_sp.contains(error.obligation.cause.span) {
+                continue
+            }
+
+            if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
+                // Collect the argument position for all arguments that could have caused this
+                // `FulfillmentError`.
+                let mut referenced_in = final_arg_types.iter()
+                    .map(|(i, checked_ty, _)| (i, checked_ty))
+                    .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty)))
+                    .flat_map(|(i, ty)| {
+                        let ty = self.resolve_vars_if_possible(ty);
+                        // We walk the argument type because the argument's type could have
+                        // been `Option<T>`, but the `FulfillmentError` references `T`.
+                        ty.walk()
+                            .filter(|&ty| ty == predicate.skip_binder().self_ty())
+                            .map(move |_| *i)
+                    })
+                    .collect::<Vec<_>>();
 
-                    // Both checked and coerced types could have matched, thus we need to remove
-                    // duplicates.
-                    referenced_in.dedup();
+                // Both checked and coerced types could have matched, thus we need to remove
+                // duplicates.
+                referenced_in.dedup();
 
-                    if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
-                        // We make sure that only *one* argument matches the obligation failure
-                        // and we assign the obligation's span to its expression's.
-                        error.obligation.cause.span = args[ref_in].span;
-                        error.points_at_arg_span = true;
-                    }
+                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+                    // We make sure that only *one* argument matches the obligation failure
+                    // and we assign 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/test/ui/issues/issue-66923.rs b/src/test/ui/issues/issue-66923.rs
new file mode 100644
index 00000000000..a452e6384a3
--- /dev/null
+++ b/src/test/ui/issues/issue-66923.rs
@@ -0,0 +1,13 @@
+fn main() {
+    let v = vec![1_f64, 2.2_f64];
+    let mut fft: Vec<Vec<f64>> = vec![];
+
+    let x1: &[f64] = &v;
+    let x2: Vec<f64> = x1.into_iter().collect();
+    //~^ ERROR a collection of type
+    fft.push(x2);
+
+    let x3 = x1.into_iter().collect::<Vec<f64>>();
+    //~^ ERROR a collection of type
+    fft.push(x3);
+}
diff --git a/src/test/ui/issues/issue-66923.stderr b/src/test/ui/issues/issue-66923.stderr
new file mode 100644
index 00000000000..a2eec7caee5
--- /dev/null
+++ b/src/test/ui/issues/issue-66923.stderr
@@ -0,0 +1,19 @@
+error[E0277]: a collection of type `std::vec::Vec<f64>` cannot be built from an iterator over elements of type `&f64`
+  --> $DIR/issue-66923.rs:6:39
+   |
+LL |     let x2: Vec<f64> = x1.into_iter().collect();
+   |                                       ^^^^^^^ a collection of type `std::vec::Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
+   |
+   = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec<f64>`
+
+error[E0277]: a collection of type `std::vec::Vec<f64>` cannot be built from an iterator over elements of type `&f64`
+  --> $DIR/issue-66923.rs:10:29
+   |
+LL |     let x3 = x1.into_iter().collect::<Vec<f64>>();
+   |                             ^^^^^^^ a collection of type `std::vec::Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
+   |
+   = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec<f64>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.