]> git.lizzy.rs Git - rust.git/commitdiff
Point at specific field in struct literal when trait fulfillment fails
authorNathan Fenner <nfenneremail@gmail.com>
Wed, 4 Jan 2023 03:54:11 +0000 (19:54 -0800)
committerNathan Fenner <nfenneremail@gmail.com>
Mon, 23 Jan 2023 21:37:58 +0000 (13:37 -0800)
21 files changed:
compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs [new file with mode: 0644]
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
compiler/rustc_hir_typeck/src/method/probe.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/tools/cargo
tests/ui/derives/deriving-copyclone.stderr
tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs [new file with mode: 0644]
tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr [new file with mode: 0644]
tests/ui/errors/traits/blame-trait-error-spans-on-exprs.rs [new file with mode: 0644]
tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr [new file with mode: 0644]
tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs
tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr
tests/ui/traits/negative-impls/negated-auto-traits-error.stderr

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
new file mode 100644 (file)
index 0000000..2eab680
--- /dev/null
@@ -0,0 +1,457 @@
+use crate::FnCtxt;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_trait_selection::traits;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /**
+     * Recursively searches for the most-specific blamable expression.
+     * For example, if you have a chain of constraints like:
+     * - want `Vec<i32>: Copy`
+     * - because `Option<Vec<i32>>: Copy` needs `Vec<i32>: Copy` because `impl <T: Copy> Copy for Option<T>`
+     * - because `(Option<Vec<i32>, bool)` needs `Option<Vec<i32>>: Copy` because `impl <A: Copy, B: Copy> Copy for (A, B)`
+     * then if you pass in `(Some(vec![1, 2, 3]), false)`, this helper `point_at_specific_expr_if_possible`
+     * will find the expression `vec![1, 2, 3]` as the "most blameable" reason for this missing constraint.
+     *
+     * This function only updates the error span.
+     */
+    pub fn blame_specific_expr_if_possible(
+        &self,
+        error: &mut traits::FulfillmentError<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) {
+        // Whether it succeeded or failed, it likely made some amount of progress.
+        // In the very worst case, it's just the same `expr` we originally passed in.
+        let expr = match self.blame_specific_expr_if_possible_for_obligation_cause_code(
+            &error.obligation.cause.code(),
+            expr,
+        ) {
+            Ok(expr) => expr,
+            Err(expr) => expr,
+        };
+
+        // Either way, use this expression to update the error span.
+        // If it doesn't overlap the existing span at all, use the original span.
+        // FIXME: It would possibly be better to do this more continuously, at each level...
+        error.obligation.cause.span = expr
+            .span
+            .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+            .unwrap_or(error.obligation.cause.span);
+    }
+
+    fn blame_specific_expr_if_possible_for_obligation_cause_code(
+        &self,
+        obligation_cause_code: &traits::ObligationCauseCode<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
+        match obligation_cause_code {
+            traits::ObligationCauseCode::ExprBindingObligation(_, _, _, _) => {
+                // This is the "root"; we assume that the `expr` is already pointing here.
+                // Therefore, we return `Ok` so that this `expr` can be refined further.
+                Ok(expr)
+            }
+            traits::ObligationCauseCode::ImplDerivedObligation(impl_derived) => self
+                .blame_specific_expr_if_possible_for_derived_predicate_obligation(
+                    impl_derived,
+                    expr,
+                ),
+            _ => {
+                // We don't recognize this kind of constraint, so we cannot refine the expression
+                // any further.
+                Err(expr)
+            }
+        }
+    }
+
+    /// We want to achieve the error span in the following example:
+    ///
+    /// ```ignore (just for demonstration)
+    /// struct Burrito<Filling> {
+    ///   filling: Filling,
+    /// }
+    /// impl <Filling: Delicious> Delicious for Burrito<Filling> {}
+    /// fn eat_delicious_food<Food: Delicious>(_food: Food) {}
+    ///
+    /// fn will_type_error() {
+    ///   eat_delicious_food(Burrito { filling: Kale });
+    /// } //                                    ^--- The trait bound `Kale: Delicious`
+    ///   //                                         is not satisfied
+    /// ```
+    ///
+    /// Without calling this function, the error span will cover the entire argument expression.
+    ///
+    /// Before we do any of this logic, we recursively call `point_at_specific_expr_if_possible` on the parent
+    /// obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize.
+    ///
+    /// This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be
+    /// reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be
+    /// only a partial success - but it cannot be refined even further.
+    fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
+        &self,
+        obligation: &traits::ImplDerivedObligationCause<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
+        // First, we attempt to refine the `expr` for our span using the parent obligation.
+        // If this cannot be done, then we are already stuck, so we stop early (hence the use
+        // of the `?` try operator here).
+        let expr = self.blame_specific_expr_if_possible_for_obligation_cause_code(
+            &*obligation.derived.parent_code,
+            expr,
+        )?;
+
+        // This is the "trait" (meaning, the predicate "proved" by this `impl`) which provides the `Self` type we care about.
+        // For the purposes of this function, we hope that it is a `struct` type, and that our current `expr` is a literal of
+        // that struct type.
+        let impl_trait_self_ref: Option<ty::TraitRef<'tcx>> =
+            self.tcx.impl_trait_ref(obligation.impl_def_id).map(|impl_def| impl_def.skip_binder());
+
+        let Some(impl_trait_self_ref) = impl_trait_self_ref else {
+            // It is possible that this is absent. In this case, we make no progress.
+            return Err(expr);
+        };
+
+        // We only really care about the `Self` type itself, which we extract from the ref.
+        let impl_self_ty: Ty<'tcx> = impl_trait_self_ref.self_ty();
+
+        let impl_predicates: ty::GenericPredicates<'tcx> =
+            self.tcx.predicates_of(obligation.impl_def_id);
+        let Some(impl_predicate_index) = obligation.impl_def_predicate_index else {
+            // We don't have the index, so we can only guess.
+            return Err(expr);
+        };
+
+        if impl_predicate_index >= impl_predicates.predicates.len() {
+            // This shouldn't happen, but since this is only a diagnostic improvement, avoid breaking things.
+            return Err(expr);
+        }
+        let relevant_broken_predicate: ty::PredicateKind<'tcx> =
+            impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder();
+
+        match relevant_broken_predicate {
+            ty::PredicateKind::Clause(ty::Clause::Trait(broken_trait)) => {
+                // ...
+                self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                    broken_trait.trait_ref.self_ty().into(),
+                    expr,
+                    impl_self_ty.into(),
+                )
+            }
+            _ => Err(expr),
+        }
+    }
+
+    /// Drills into `expr` to arrive at the equivalent location of `find_generic_param` in `in_ty`.
+    /// For example, given
+    /// - expr: `(Some(vec![1, 2, 3]), false)`
+    /// - param: `T`
+    /// - in_ty: `(Option<Vec<T>, bool)`
+    /// we would drill until we arrive at `vec![1, 2, 3]`.
+    ///
+    /// If successful, we return `Ok(refined_expr)`. If unsuccesful, we return `Err(partially_refined_expr`),
+    /// which will go as far as possible. For example, given `(foo(), false)` instead, we would drill to
+    /// `foo()` and then return `Err("foo()")`.
+    ///
+    /// This means that you can (and should) use the `?` try operator to chain multiple calls to this
+    /// function with different types, since you can only continue drilling the second time if you
+    /// succeeded the first time.
+    fn blame_specific_part_of_expr_corresponding_to_generic_param(
+        &self,
+        param: ty::GenericArg<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+        in_ty: ty::GenericArg<'tcx>,
+    ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
+        if param == in_ty {
+            // The types match exactly, so we have drilled as far as we can.
+            return Ok(expr);
+        }
+
+        let ty::GenericArgKind::Type(in_ty) = in_ty.unpack() else {
+            return Err(expr);
+        };
+
+        if let (hir::ExprKind::Tup(expr_elements), ty::Tuple(in_ty_elements)) =
+            (&expr.kind, in_ty.kind())
+        {
+            if in_ty_elements.len() != expr_elements.len() {
+                return Err(expr);
+            }
+            // Find out which of `in_ty_elements` refer to `param`.
+            // FIXME: It may be better to take the first if there are multiple,
+            // just so that the error points to a smaller expression.
+            let Some((drill_expr, drill_ty)) = Self::is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| {
+                Self::find_param_in_ty((*in_ty_elem).into(), param)
+            })) else {
+                // The param is not mentioned, or it is mentioned in multiple indexes.
+                return Err(expr);
+            };
+
+            return self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param,
+                drill_expr,
+                drill_ty.into(),
+            );
+        }
+
+        if let (
+            hir::ExprKind::Struct(expr_struct_path, expr_struct_fields, _expr_struct_rest),
+            ty::Adt(in_ty_adt, in_ty_adt_generic_args),
+        ) = (&expr.kind, in_ty.kind())
+        {
+            // First, confirm that this struct is the same one as in the types, and if so,
+            // find the right variant.
+            let Res::Def(expr_struct_def_kind, expr_struct_def_id) = self.typeck_results.borrow().qpath_res(expr_struct_path, expr.hir_id) else {
+                return Err(expr);
+            };
+
+            let variant_def_id = match expr_struct_def_kind {
+                hir::def::DefKind::Struct => {
+                    if in_ty_adt.did() != expr_struct_def_id {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    expr_struct_def_id
+                }
+                hir::def::DefKind::Variant => {
+                    // If this is a variant, its parent is the type definition.
+                    if in_ty_adt.did() != self.tcx.parent(expr_struct_def_id) {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    expr_struct_def_id
+                }
+                _ => {
+                    return Err(expr);
+                }
+            };
+
+            // We need to know which of the generic parameters mentions our target param.
+            // We expect that at least one of them does, since it is expected to be mentioned.
+            let Some((drill_generic_index, generic_argument_type)) =
+                Self::is_iterator_singleton(
+                    in_ty_adt_generic_args.iter().enumerate().filter(
+                        |(_index, in_ty_generic)| {
+                            Self::find_param_in_ty(*in_ty_generic, param)
+                        },
+                    ),
+                ) else {
+                    return Err(expr);
+                };
+
+            let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
+            if drill_generic_index >= struct_generic_parameters.params.len() {
+                return Err(expr);
+            }
+
+            let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
+                struct_generic_parameters.param_at(drill_generic_index, self.tcx),
+            );
+
+            // We make 3 steps:
+            // Suppose we have a type like
+            // ```ignore (just for demonstration)
+            // struct ExampleStruct<T> {
+            //   enabled: bool,
+            //   item: Option<(usize, T, bool)>,
+            // }
+            //
+            // f(ExampleStruct {
+            //   enabled: false,
+            //   item: Some((0, Box::new(String::new()), 1) }, true)),
+            // });
+            // ```
+            // Here, `f` is passed a `ExampleStruct<Box<String>>`, but it wants
+            // for `String: Copy`, which isn't true here.
+            //
+            // (1) First, we drill into `.item` and highlight that expression
+            // (2) Then we use the template type `Option<(usize, T, bool)>` to
+            //     drill into the `T`, arriving at a `Box<String>` expression.
+            // (3) Then we keep going, drilling into this expression using our
+            //     outer contextual information.
+
+            // (1) Find the (unique) field which mentions the type in our constraint:
+            let (field_expr, field_type) = self
+                .point_at_field_if_possible(
+                    in_ty_adt.did(),
+                    param_to_point_at_in_struct,
+                    variant_def_id,
+                    expr_struct_fields,
+                )
+                .ok_or(expr)?;
+
+            // (2) Continue drilling into the struct, ignoring the struct's
+            // generic argument types.
+            let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param_to_point_at_in_struct,
+                field_expr,
+                field_type.into(),
+            )?;
+
+            // (3) Continue drilling into the expression, having "passed
+            // through" the struct entirely.
+            return self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param,
+                expr,
+                generic_argument_type,
+            );
+        }
+
+        if let (
+            hir::ExprKind::Call(expr_callee, expr_args),
+            ty::Adt(in_ty_adt, in_ty_adt_generic_args),
+        ) = (&expr.kind, in_ty.kind())
+        {
+            let hir::ExprKind::Path(expr_callee_path) = &expr_callee.kind else {
+                // FIXME: This case overlaps with another one worth handling,
+                // which should happen above since it applies to non-ADTs:
+                // we can drill down into regular generic functions.
+                return Err(expr);
+            };
+            // This is (possibly) a constructor call, like `Some(...)` or `MyStruct(a, b, c)`.
+
+            let Res::Def(expr_struct_def_kind, expr_ctor_def_id) = self.typeck_results.borrow().qpath_res(expr_callee_path, expr_callee.hir_id) else {
+                return Err(expr);
+            };
+
+            let variant_def_id = match expr_struct_def_kind {
+                hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, hir::def::CtorKind::Fn) => {
+                    if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    self.tcx.parent(expr_ctor_def_id)
+                }
+                hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
+                    // If this is a variant, its parent is the type definition.
+                    if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
+                        // FIXME: Deal with type aliases?
+                        return Err(expr);
+                    }
+                    expr_ctor_def_id
+                }
+                _ => {
+                    return Err(expr);
+                }
+            };
+
+            // We need to know which of the generic parameters mentions our target param.
+            // We expect that at least one of them does, since it is expected to be mentioned.
+            let Some((drill_generic_index, generic_argument_type)) =
+                Self::is_iterator_singleton(
+                    in_ty_adt_generic_args.iter().enumerate().filter(
+                        |(_index, in_ty_generic)| {
+                            Self::find_param_in_ty(*in_ty_generic, param)
+                        },
+                    ),
+                ) else {
+                    return Err(expr);
+                };
+
+            let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
+            if drill_generic_index >= struct_generic_parameters.params.len() {
+                return Err(expr);
+            }
+
+            let param_to_point_at_in_struct = self.tcx.mk_param_from_def(
+                struct_generic_parameters.param_at(drill_generic_index, self.tcx),
+            );
+
+            // We make 3 steps:
+            // Suppose we have a type like
+            // ```ignore (just for demonstration)
+            // struct ExampleStruct<T> {
+            //   enabled: bool,
+            //   item: Option<(usize, T, bool)>,
+            // }
+            //
+            // f(ExampleStruct {
+            //   enabled: false,
+            //   item: Some((0, Box::new(String::new()), 1) }, true)),
+            // });
+            // ```
+            // Here, `f` is passed a `ExampleStruct<Box<String>>`, but it wants
+            // for `String: Copy`, which isn't true here.
+            //
+            // (1) First, we drill into `.item` and highlight that expression
+            // (2) Then we use the template type `Option<(usize, T, bool)>` to
+            //     drill into the `T`, arriving at a `Box<String>` expression.
+            // (3) Then we keep going, drilling into this expression using our
+            //     outer contextual information.
+
+            // (1) Find the (unique) field index which mentions the type in our constraint:
+            let Some((field_index, field_type)) = Self::is_iterator_singleton(
+                in_ty_adt
+                    .variant_with_id(variant_def_id)
+                    .fields
+                    .iter()
+                    .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args))
+                    .enumerate()
+                    .filter(|(_index, field_type)| Self::find_param_in_ty((*field_type).into(), param))
+            ) else {
+                return Err(expr);
+            };
+
+            if field_index >= expr_args.len() {
+                return Err(expr);
+            }
+
+            // (2) Continue drilling into the struct, ignoring the struct's
+            // generic argument types.
+            let expr = self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param_to_point_at_in_struct,
+                &expr_args[field_index],
+                field_type.into(),
+            )?;
+
+            // (3) Continue drilling into the expression, having "passed
+            // through" the struct entirely.
+            return self.blame_specific_part_of_expr_corresponding_to_generic_param(
+                param,
+                expr,
+                generic_argument_type,
+            );
+        }
+
+        // At this point, none of the basic patterns matched.
+        // One major possibility which remains is that we have a function call.
+        // In this case, it's often possible to dive deeper into the call to find something to blame,
+        // but this is not always possible.
+
+        Err(expr)
+    }
+
+    // FIXME: This can be made into a private, non-impl function later.
+    /// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references
+    /// to the given `param_to_point_at`. Returns `true` if it finds any use of the param.
+    pub fn find_param_in_ty(
+        ty: ty::GenericArg<'tcx>,
+        param_to_point_at: ty::GenericArg<'tcx>,
+    ) -> bool {
+        let mut walk = ty.walk();
+        while let Some(arg) = walk.next() {
+            if arg == param_to_point_at {
+            return true;
+        } else if let ty::GenericArgKind::Type(ty) = arg.unpack()
+            && let ty::Alias(ty::Projection, ..) = ty.kind()
+        {
+            // This logic may seem a bit strange, but typically when
+            // we have a projection type in a function signature, the
+            // argument that's being passed into that signature is
+            // not actually constraining that projection's substs in
+            // a meaningful way. So we skip it, and see improvements
+            // in some UI tests.
+            walk.skip_current_subtree();
+        }
+        }
+        false
+    }
+
+    // FIXME: This can be made into a private, non-impl function later.
+    /// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise.
+    pub fn is_iterator_singleton<T>(mut iterator: impl Iterator<Item = T>) -> Option<T> {
+        match (iterator.next(), iterator.next()) {
+            (_, Some(_)) => None,
+            (first, _) => first,
+        }
+    }
+}
index c9609e69439812477b27d84f3d037abe82167ea0..56b256cfbe4febc62544dc891da8ab6263bcee83 100644 (file)
 
 use std::iter;
 use std::mem;
-use std::ops::ControlFlow;
 use std::slice;
 
+use std::ops::ControlFlow;
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_casts(&mut self) {
         // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
@@ -1837,7 +1838,7 @@ fn adjust_fulfillment_error_for_expr_obligation(
                         .into_iter()
                         .flatten()
                     {
-                        if self.point_at_arg_if_possible(
+                        if self.blame_specific_arg_if_possible(
                                 error,
                                 def_id,
                                 param,
@@ -1867,7 +1868,7 @@ fn adjust_fulfillment_error_for_expr_obligation(
                     .into_iter()
                     .flatten()
                 {
-                    if self.point_at_arg_if_possible(
+                    if self.blame_specific_arg_if_possible(
                         error,
                         def_id,
                         param,
@@ -1892,16 +1893,24 @@ fn adjust_fulfillment_error_for_expr_obligation(
                     for param in
                         [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
                     {
-                        if let Some(param) = param
-                            && self.point_at_field_if_possible(
-                                error,
+                        if let Some(param) = param {
+                            let refined_expr = self.point_at_field_if_possible(
                                 def_id,
                                 param,
                                 variant_def_id,
                                 fields,
-                            )
-                        {
-                            return true;
+                            );
+
+                            match refined_expr {
+                                None => {}
+                                Some((refined_expr, _)) => {
+                                    error.obligation.cause.span = refined_expr
+                                        .span
+                                        .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+                                        .unwrap_or(refined_expr.span);
+                                    return true;
+                                }
+                            }
                         }
                     }
                 }
@@ -1934,7 +1943,16 @@ fn closure_span_overlaps_error(
         }
     }
 
-    fn point_at_arg_if_possible(
+    /// - `blame_specific_*` means that the function will recursively traverse the expression,
+    /// looking for the most-specific-possible span to blame.
+    ///
+    /// - `point_at_*` means that the function will only go "one level", pointing at the specific
+    /// expression mentioned.
+    ///
+    /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
+    /// the provided function call expression, and mark it as responsible for the fullfillment
+    /// error.
+    fn blame_specific_arg_if_possible(
         &self,
         error: &mut traits::FulfillmentError<'tcx>,
         def_id: DefId,
@@ -1953,13 +1971,20 @@ fn point_at_arg_if_possible(
             .inputs()
             .iter()
             .enumerate()
-            .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
+            .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
             .collect();
         // If there's one field that references the given generic, great!
         if let [(idx, _)] = args_referencing_param.as_slice()
             && let Some(arg) = receiver
                 .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
+
             error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
+
+            if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
+                // This is more specific than pointing at the entire argument.
+                self.blame_specific_expr_if_possible(error, arg_expr)
+            }
+
             error.obligation.cause.map_code(|parent_code| {
                 ObligationCauseCode::FunctionArgumentObligation {
                     arg_hir_id: arg.hir_id,
@@ -1977,14 +2002,14 @@ fn point_at_arg_if_possible(
         false
     }
 
-    fn point_at_field_if_possible(
+    // FIXME: Make this private and move to mod adjust_fulfillment_errors
+    pub fn point_at_field_if_possible(
         &self,
-        error: &mut traits::FulfillmentError<'tcx>,
         def_id: DefId,
         param_to_point_at: ty::GenericArg<'tcx>,
         variant_def_id: DefId,
         expr_fields: &[hir::ExprField<'tcx>],
-    ) -> bool {
+    ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
         let def = self.tcx.adt_def(def_id);
 
         let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
@@ -1994,7 +2019,7 @@ fn point_at_field_if_possible(
             .iter()
             .filter(|field| {
                 let field_ty = field.ty(self.tcx, identity_substs);
-                find_param_in_ty(field_ty, param_to_point_at)
+                Self::find_param_in_ty(field_ty.into(), param_to_point_at)
             })
             .collect();
 
@@ -2004,17 +2029,12 @@ fn point_at_field_if_possible(
                 // same rules that check_expr_struct uses for macro hygiene.
                 if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
                 {
-                    error.obligation.cause.span = expr_field
-                        .expr
-                        .span
-                        .find_ancestor_in_same_ctxt(error.obligation.cause.span)
-                        .unwrap_or(expr_field.span);
-                    return true;
+                    return Some((expr_field.expr, self.tcx.type_of(field.did)));
                 }
             }
         }
 
-        false
+        None
     }
 
     fn point_at_path_if_possible(
@@ -2234,23 +2254,3 @@ fn label_fn_like(
         }
     }
 }
-
-fn find_param_in_ty<'tcx>(ty: Ty<'tcx>, param_to_point_at: ty::GenericArg<'tcx>) -> bool {
-    let mut walk = ty.walk();
-    while let Some(arg) = walk.next() {
-        if arg == param_to_point_at {
-            return true;
-        } else if let ty::GenericArgKind::Type(ty) = arg.unpack()
-            && let ty::Alias(ty::Projection, ..) = ty.kind()
-        {
-            // This logic may seem a bit strange, but typically when
-            // we have a projection type in a function signature, the
-            // argument that's being passed into that signature is
-            // not actually constraining that projection's substs in
-            // a meaningful way. So we skip it, and see improvements
-            // in some UI tests.
-            walk.skip_current_subtree();
-        }
-    }
-    false
-}
index 428fde642bc0901bff4a7fb92c8c6cb6c589c100..b1f9a020964531388c3b28c05caccd29c124259b 100644 (file)
@@ -1,4 +1,5 @@
 mod _impl;
+mod adjust_fulfillment_errors;
 mod arg_matrix;
 mod checks;
 mod suggestions;
index 9c06a22315bcba12189377e2770e9884588d5e5f..87f5857986b545904304e883286f98b1b0fdc422 100644 (file)
@@ -1568,6 +1568,7 @@ fn consider_probe(
                                     traits::ImplDerivedObligationCause {
                                         derived,
                                         impl_def_id,
+                                        impl_def_predicate_index: None,
                                         span,
                                     },
                                 ))
index cd5bde2a791309c6c0f6d5aa6d73a55e412e0e36..18a966449aa72f2e9432ab3c833d8bdc1ba22bae 100644 (file)
@@ -145,30 +145,32 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
                 // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
-                let obligations = predicates.predicates.iter().map(|&(mut pred, span)| {
-                    // when parent predicate is non-const, elaborate it to non-const predicates.
-                    if data.constness == ty::BoundConstness::NotConst {
-                        pred = pred.without_const(tcx);
-                    }
-
-                    let cause = obligation.cause.clone().derived_cause(
-                        bound_predicate.rebind(data),
-                        |derived| {
-                            traits::ImplDerivedObligation(Box::new(
-                                traits::ImplDerivedObligationCause {
-                                    derived,
-                                    impl_def_id: data.def_id(),
-                                    span,
-                                },
-                            ))
-                        },
-                    );
-                    predicate_obligation(
-                        pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
-                        obligation.param_env,
-                        cause,
-                    )
-                });
+                let obligations =
+                    predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
+                        // when parent predicate is non-const, elaborate it to non-const predicates.
+                        if data.constness == ty::BoundConstness::NotConst {
+                            pred = pred.without_const(tcx);
+                        }
+
+                        let cause = obligation.cause.clone().derived_cause(
+                            bound_predicate.rebind(data),
+                            |derived| {
+                                traits::ImplDerivedObligation(Box::new(
+                                    traits::ImplDerivedObligationCause {
+                                        derived,
+                                        impl_def_id: data.def_id(),
+                                        impl_def_predicate_index: Some(index),
+                                        span,
+                                    },
+                                ))
+                            },
+                        );
+                        predicate_obligation(
+                            pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
+                            obligation.param_env,
+                            cause,
+                        )
+                    });
                 debug!(?data, ?obligations, "super_predicates");
 
                 // Only keep those bounds that we haven't already seen.
index d00b26a5a3d0b42baafca1d795332bbfc0ddbdcc..b26ef2a29931f4948920e1750d651d9f5e630fa6 100644 (file)
@@ -467,6 +467,8 @@ pub enum WellFormedLoc {
 pub struct ImplDerivedObligationCause<'tcx> {
     pub derived: DerivedObligationCause<'tcx>,
     pub impl_def_id: DefId,
+    /// The index of the derived predicate in the parent impl's predicates.
+    pub impl_def_predicate_index: Option<usize>,
     pub span: Span,
 }
 
index 82a59831be30aec5ff9791487cec5b72f6df7ca6..4aeaf3ce7144eeb9d06611a908012ab6af2d8ef2 100644 (file)
@@ -1224,6 +1224,7 @@ fn confirm_const_destruct_candidate(
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
                     derived,
                     impl_def_id,
+                    impl_def_predicate_index: None,
                     span: obligation.cause.span,
                 }))
             });
index f90da95d51668b56cfbb582cbae2231ef6db371f..7bfc098e4cdf7746e608068a95c0be606f1ac1c5 100644 (file)
@@ -2562,11 +2562,12 @@ fn impl_or_trait_obligations(
         assert_eq!(predicates.parent, None);
         let predicates = predicates.instantiate_own(tcx, substs);
         let mut obligations = Vec::with_capacity(predicates.len());
-        for (predicate, span) in predicates {
+        for (index, (predicate, span)) in predicates.into_iter().enumerate() {
             let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
                     derived,
                     impl_def_id: def_id,
+                    impl_def_predicate_index: Some(index),
                     span,
                 }))
             });
index 2cd1b5593d26dc6a03c20f8619187ad4b2485552..2bd5d42c9956369132228da6409f0e68da56c51a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2cd1b5593d26dc6a03c20f8619187ad4b2485552
+Subproject commit 2bd5d42c9956369132228da6409f0e68da56c51a
index 960d610e7f33889a2577f5f17c26f0d5c82b30df..8ca261268068d80c0969260fff15199bad87b587 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 960d610e7f33889a2577f5f17c26f0d5c82b30df
+Subproject commit 8ca261268068d80c0969260fff15199bad87b587
index 2cb0ed9ba56360949f492f9866afe8c293f9f9da..3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2cb0ed9ba56360949f492f9866afe8c293f9f9da
+Subproject commit 3ae62681ff236d5528ef7c8c28ba7c6b2ecc6731
index a9fb7d13eadfcc5f457962731f105b97f9a7474a..8888f9428fe9a48f31de6bd2cef9b9bf80791edc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a9fb7d13eadfcc5f457962731f105b97f9a7474a
+Subproject commit 8888f9428fe9a48f31de6bd2cef9b9bf80791edc
index 985d561f0bb9b76ec043a2b12511790ec7a2b954..8c460b2237a6359a7e3335890db8da049bdd62fc 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 985d561f0bb9b76ec043a2b12511790ec7a2b954
+Subproject commit 8c460b2237a6359a7e3335890db8da049bdd62fc
index 9c4ca01ff377778a6ca5ed8a89988d777e7f68da..c0c2215c04adb44d520aa84fe983587948d661a0 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `B<C>: Copy` is not satisfied
-  --> $DIR/deriving-copyclone.rs:31:13
+  --> $DIR/deriving-copyclone.rs:31:26
    |
 LL |     is_copy(B { a: 1, b: C });
-   |     ------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `B<C>`
+   |     -------              ^ the trait `Copy` is not implemented for `B<C>`
    |     |
    |     required by a bound introduced by this call
    |
@@ -19,14 +19,14 @@ LL | fn is_copy<T: Copy>(_: T) {}
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
-LL |     is_copy(&B { a: 1, b: C });
-   |             +
+LL |     is_copy(B { a: 1, b: &C });
+   |                          +
 
 error[E0277]: the trait bound `B<C>: Clone` is not satisfied
-  --> $DIR/deriving-copyclone.rs:32:14
+  --> $DIR/deriving-copyclone.rs:32:27
    |
 LL |     is_clone(B { a: 1, b: C });
-   |     -------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B<C>`
+   |     --------              ^ the trait `Clone` is not implemented for `B<C>`
    |     |
    |     required by a bound introduced by this call
    |
@@ -43,14 +43,14 @@ LL | fn is_clone<T: Clone>(_: T) {}
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
-LL |     is_clone(&B { a: 1, b: C });
-   |              +
+LL |     is_clone(B { a: 1, b: &C });
+   |                           +
 
 error[E0277]: the trait bound `B<D>: Copy` is not satisfied
-  --> $DIR/deriving-copyclone.rs:35:13
+  --> $DIR/deriving-copyclone.rs:35:26
    |
 LL |     is_copy(B { a: 1, b: D });
-   |     ------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `B<D>`
+   |     -------              ^ the trait `Copy` is not implemented for `B<D>`
    |     |
    |     required by a bound introduced by this call
    |
@@ -67,8 +67,8 @@ LL | fn is_copy<T: Copy>(_: T) {}
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider borrowing here
    |
-LL |     is_copy(&B { a: 1, b: D });
-   |             +
+LL |     is_copy(B { a: 1, b: &D });
+   |                          +
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs
new file mode 100644 (file)
index 0000000..5134c67
--- /dev/null
@@ -0,0 +1,28 @@
+trait T1 {}
+trait T2 {}
+trait T3 {}
+trait T4 {}
+
+impl<B: T2> T1 for Wrapper<B> {}
+
+impl T2 for i32 {}
+impl T3 for i32 {}
+
+impl<A: T3> T2 for Burrito<A> {}
+
+struct Wrapper<W> {
+    value: W,
+}
+
+struct Burrito<F> {
+    filling: F,
+}
+
+fn want<V: T1>(_x: V) {}
+
+fn example<Q>(q: Q) {
+    want(Wrapper { value: Burrito { filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+}
+
+fn main() {}
diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
new file mode 100644 (file)
index 0000000..27b002d
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error.rs:24:46
+   |
+LL |     want(Wrapper { value: Burrito { filling: q } });
+   |     ----                                     ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `Burrito<Q>` to implement `T2`
+  --> $DIR/blame-trait-error.rs:11:13
+   |
+LL | impl<A: T3> T2 for Burrito<A> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<Burrito<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error.rs:6:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error.rs:21:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.rs b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.rs
new file mode 100644 (file)
index 0000000..2b75f43
--- /dev/null
@@ -0,0 +1,131 @@
+// This test examines the error spans reported when a generic `impl` fails.
+// For example, if a function wants an `Option<T>` where `T: Copy` but you pass `Some(vec![1, 2])`,
+// then we want to point at the `vec![1, 2]` and not the `Some( ... )` expression.
+
+trait T1 {}
+trait T2 {}
+trait T3 {}
+trait T4 {}
+
+impl T2 for i32 {}
+impl T3 for i32 {}
+
+struct Wrapper<W> {
+    value: W,
+}
+impl<B: T2> T1 for Wrapper<B> {}
+
+struct Burrito<F> {
+    spicy: bool,
+    filling: F,
+}
+impl<A: T3> T2 for Burrito<A> {}
+
+struct BurritoTuple<F>(F);
+impl<C: T3> T2 for BurritoTuple<C> {}
+
+enum BurritoKinds<G> {
+    SmallBurrito { spicy: bool, small_filling: G },
+    LargeBurrito { spicy: bool, large_filling: G },
+    MultiBurrito { first_filling: G, second_filling: G },
+}
+impl<D: T3> T2 for BurritoKinds<D> {}
+
+struct Taco<H>(bool, H);
+impl<E: T3> T2 for Taco<E> {}
+
+enum TacoKinds<H> {
+    OneTaco(bool, H),
+    TwoTacos(bool, H, H),
+}
+impl<F: T3> T2 for TacoKinds<F> {}
+
+struct GenericBurrito<Spiciness, Filling> {
+    spiciness: Spiciness,
+    filling: Filling,
+}
+impl<X, Y: T3> T2 for GenericBurrito<X, Y> {}
+struct NotSpicy;
+
+impl<A: T3, B: T3> T2 for (A, B) {}
+impl<A: T2, B: T2> T1 for (A, B) {}
+
+fn want<V: T1>(_x: V) {}
+
+// Some more-complex examples:
+type AliasBurrito<T> = GenericBurrito<T, T>;
+
+// The following example is fairly confusing. The idea is that we want to "misdirect" the location
+// of the error.
+
+struct Two<A, B> {
+    a: A,
+    b: B,
+}
+
+impl<X, Y: T1, Z> T1 for Two<Two<X, Y>, Z> {}
+
+struct DoubleWrapper<T> {
+    item: Wrapper<T>,
+}
+
+impl<T: T1> T1 for DoubleWrapper<T> {}
+
+fn example<Q>(q: Q) {
+    // In each of the following examples, we expect the error span to point at the 'q' variable,
+    // since the missing constraint is `Q: T3`.
+
+    // Verifies for struct:
+    want(Wrapper { value: Burrito { spicy: false, filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for enum with named fields in variant:
+    want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for tuple struct:
+    want(Wrapper { value: Taco(false, q) });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for tuple enum variant:
+    want(Wrapper { value: TacoKinds::OneTaco(false, q) });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for generic type with multiple parameters:
+    want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for tuple:
+    want((3, q));
+    //~^ ERROR the trait bound `Q: T2` is not satisfied [E0277]
+
+    // Verifies for nested tuple:
+    want(Wrapper { value: (3, q) });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    // Verifies for nested tuple:
+    want(((3, q), 5));
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    want(DoubleWrapper { item: Wrapper { value: q } });
+    //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+
+    want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } });
+    //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+
+    // Verifies for type alias to struct:
+    want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } });
+    //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277]
+
+    want(Two { a: Two { a: (), b: q }, b: () });
+    //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+
+    // We *should* blame the 'q'.
+    // FIXME: Right now, the wrong field is blamed.
+    want(
+        Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () },
+        //~^ ERROR the trait bound `Q: T1` is not satisfied [E0277]
+    );
+}
+
+fn main() {}
diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
new file mode 100644 (file)
index 0000000..5f87c67
--- /dev/null
@@ -0,0 +1,380 @@
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:79:60
+   |
+LL |     want(Wrapper { value: Burrito { spicy: false, filling: q } });
+   |     ---- required by a bound introduced by this call       ^ the trait `T3` is not implemented for `Q`
+   |
+note: required for `Burrito<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:22:13
+   |
+LL | impl<A: T3> T2 for Burrito<A> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<Burrito<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:83:84
+   |
+LL |     want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
+   |     ---- required by a bound introduced by this call                               ^ the trait `T3` is not implemented for `Q`
+   |
+note: required for `BurritoKinds<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:32:13
+   |
+LL | impl<D: T3> T2 for BurritoKinds<D> {}
+   |         --  ^^     ^^^^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<BurritoKinds<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:87:39
+   |
+LL |     want(Wrapper { value: Taco(false, q) });
+   |     ----                              ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `Taco<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:35:13
+   |
+LL | impl<E: T3> T2 for Taco<E> {}
+   |         --  ^^     ^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<Taco<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:91:27
+   |
+LL |     want(Wrapper { value: TacoKinds::OneTaco(false, q) });
+   |     ----                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `TacoKinds<Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:41:13
+   |
+LL | impl<F: T3> T2 for TacoKinds<F> {}
+   |         --  ^^     ^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required for `Wrapper<TacoKinds<Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:95:74
+   |
+LL |     want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } });
+   |     ---- required by a bound introduced by this call                     ^ the trait `T3` is not implemented for `Q`
+   |
+note: required for `GenericBurrito<NotSpicy, Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:47:16
+   |
+LL | impl<X, Y: T3> T2 for GenericBurrito<X, Y> {}
+   |            --  ^^     ^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: required for `Wrapper<GenericBurrito<NotSpicy, Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T2` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:99:14
+   |
+LL |     want((3, q));
+   |     ----     ^ the trait `T2` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `(i32, Q)` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:51:20
+   |
+LL | impl<A: T2, B: T2> T1 for (A, B) {}
+   |                --  ^^     ^^^^^^
+   |                |
+   |                unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T2>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:103:31
+   |
+LL |     want(Wrapper { value: (3, q) });
+   |     ----                      ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `(i32, Q)` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:50:20
+   |
+LL | impl<A: T3, B: T3> T2 for (A, B) {}
+   |                --  ^^     ^^^^^^
+   |                |
+   |                unsatisfied trait bound introduced here
+note: required for `Wrapper<(i32, Q)>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:107:15
+   |
+LL |     want(((3, q), 5));
+   |     ----      ^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `(i32, Q)` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:50:20
+   |
+LL | impl<A: T3, B: T3> T2 for (A, B) {}
+   |                --  ^^     ^^^^^^
+   |                |
+   |                unsatisfied trait bound introduced here
+note: required for `((i32, Q), i32)` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:51:20
+   |
+LL | impl<A: T2, B: T2> T1 for (A, B) {}
+   |         --         ^^     ^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:110:49
+   |
+LL |     want(DoubleWrapper { item: Wrapper { value: q } });
+   |     ----                                        ^ the trait `T1` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `DoubleWrapper<Q>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:72:13
+   |
+LL | impl<T: T1> T1 for DoubleWrapper<T> {}
+   |         --  ^^     ^^^^^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:113:88
+   |
+LL |     want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } });
+   |     ---- required by a bound introduced by this call                                   ^ the trait `T1` is not implemented for `Q`
+   |
+note: required for `DoubleWrapper<Q>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:72:13
+   |
+LL | impl<T: T1> T1 for DoubleWrapper<T> {}
+   |         --  ^^     ^^^^^^^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: 1 redundant requirement hidden
+   = note: required for `DoubleWrapper<DoubleWrapper<Q>>` to implement `T1`
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T3` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:117:27
+   |
+LL |     want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } });
+   |     ----                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `GenericBurrito<Q, Q>` to implement `T2`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:47:16
+   |
+LL | impl<X, Y: T3> T2 for GenericBurrito<X, Y> {}
+   |            --  ^^     ^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: required for `Wrapper<GenericBurrito<Q, Q>>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:16:13
+   |
+LL | impl<B: T2> T1 for Wrapper<B> {}
+   |         --  ^^     ^^^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T3>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:120:35
+   |
+LL |     want(Two { a: Two { a: (), b: q }, b: () });
+   |     ----                          ^ the trait `T1` is not implemented for `Q`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required for `Two<Two<(), Q>, ()>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:66:19
+   |
+LL | impl<X, Y: T1, Z> T1 for Two<Two<X, Y>, Z> {}
+   |            --     ^^     ^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error[E0277]: the trait bound `Q: T1` is not satisfied
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:126:59
+   |
+LL |     want(
+   |     ---- required by a bound introduced by this call
+LL |         Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () },
+   |                                                           ^ the trait `T1` is not implemented for `Q`
+   |
+note: required for `Two<Two<(), Q>, ()>` to implement `T1`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:66:19
+   |
+LL | impl<X, Y: T1, Z> T1 for Two<Two<X, Y>, Z> {}
+   |            --     ^^     ^^^^^^^^^^^^^^^^^
+   |            |
+   |            unsatisfied trait bound introduced here
+   = note: 1 redundant requirement hidden
+   = note: required for `Two<Two<(), Two<Two<(), Q>, ()>>, ()>` to implement `T1`
+note: required by a bound in `want`
+  --> $DIR/blame-trait-error-spans-on-exprs.rs:53:12
+   |
+LL | fn want<V: T1>(_x: V) {}
+   |            ^^ required by this bound in `want`
+help: consider restricting type parameter `Q`
+   |
+LL | fn example<Q: T1>(q: Q) {
+   |             ++++
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index e70f6fc3430f67726e0192f0119ffd3657d5cff2..6d3bb9bbb771533597efe5836c852030577de108 100644 (file)
@@ -35,16 +35,14 @@ trait Ty<'a> {
 }
 
 fn main() {
-    let v = Unit2.m(
-        L {
-            //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
-            //~| ERROR type mismatch
-            f: |x| {
-                drop(x);
-                Unit4
-            },
+    let v = Unit2.m(L {
+        //~^ ERROR type mismatch
+        //~| ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
+        f: |x| {
+            drop(x);
+            Unit4
         },
-    );
+    });
 }
 
 impl<'a> Ty<'a> for Unit2 {
index 810f7c28c004f61efa5575ec0e1426d170def6a2..9faea3a229bd61a75ec63df5019cf5c25fd0e767 100644 (file)
@@ -1,16 +1,17 @@
-error[E0271]: type mismatch resolving `for<'r> <L<[closure@issue-62203-hrtb-ice.rs:42:16]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
-  --> $DIR/issue-62203-hrtb-ice.rs:39:9
+error[E0271]: type mismatch resolving `for<'r> <L<[closure@issue-62203-hrtb-ice.rs:41:12]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+  --> $DIR/issue-62203-hrtb-ice.rs:38:21
    |
-LL |       let v = Unit2.m(
-   |                     - required by a bound introduced by this call
-LL | /         L {
+LL |       let v = Unit2.m(L {
+   |  ___________________-_^
+   | |                   |
+   | |                   required by a bound introduced by this call
 LL | |
 LL | |
-LL | |             f: |x| {
+LL | |         f: |x| {
 ...  |
-LL | |             },
 LL | |         },
-   | |_________^ type mismatch resolving `for<'r> <L<[closure@issue-62203-hrtb-ice.rs:42:16]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+LL | |     });
+   | |_____^ type mismatch resolving `for<'r> <L<[closure@issue-62203-hrtb-ice.rs:41:12]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
    |
 note: expected this to be `<_ as Ty<'_>>::V`
   --> $DIR/issue-62203-hrtb-ice.rs:21:14
@@ -30,21 +31,22 @@ LL |     where
 LL |         F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
    |                                                   ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
 
-error[E0271]: expected `[closure@issue-62203-hrtb-ice.rs:42:16]` to be a closure that returns `Unit3`, but it returns `Unit4`
-  --> $DIR/issue-62203-hrtb-ice.rs:39:9
+error[E0271]: expected `[closure@issue-62203-hrtb-ice.rs:41:12]` to be a closure that returns `Unit3`, but it returns `Unit4`
+  --> $DIR/issue-62203-hrtb-ice.rs:38:21
    |
-LL |       let v = Unit2.m(
-   |                     - required by a bound introduced by this call
-LL | /         L {
+LL |       let v = Unit2.m(L {
+   |  ___________________-_^
+   | |                   |
+   | |                   required by a bound introduced by this call
 LL | |
 LL | |
-LL | |             f: |x| {
+LL | |         f: |x| {
 ...  |
-LL | |             },
 LL | |         },
-   | |_________^ expected struct `Unit3`, found struct `Unit4`
+LL | |     });
+   | |_____^ expected struct `Unit3`, found struct `Unit4`
    |
-note: required for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>` to implement `for<'r> T0<'r, (&'r u8,)>`
+note: required for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:41:12: 41:15]>` to implement `for<'r> T0<'r, (&'r u8,)>`
   --> $DIR/issue-62203-hrtb-ice.rs:17:16
    |
 LL | impl<'a, A, T> T0<'a, A> for L<T>
index ce690b749f5512ae86f2c0905124a015f66d05ec..b680ce7f99013d67848469be9943f8771331ee39 100644 (file)
@@ -101,10 +101,10 @@ LL | fn is_send<T: Send>(_: T) {}
    |               ^^^^ required by this bound in `is_send`
 
 error[E0277]: `main::TestType` cannot be sent between threads safely
-  --> $DIR/negated-auto-traits-error.rs:66:13
+  --> $DIR/negated-auto-traits-error.rs:66:20
    |
 LL |     is_sync(Outer2(TestType));
-   |     ------- ^^^^^^^^^^^^^^^^ `main::TestType` cannot be sent between threads safely
+   |     -------        ^^^^^^^^ `main::TestType` cannot be sent between threads safely
    |     |
    |     required by a bound introduced by this call
    |