From db0324ebb2961bbeb1a75641fd1ca38d6462b721 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 18 Jul 2021 11:33:49 -0500 Subject: [PATCH] Support HIR wf checking for function signatures During function type-checking, we normalize any associated types in the function signature (argument types + return type), and then create WF obligations for each of the normalized types. The HIR wf code does not currently support this case, so any errors that we get have imprecise spans. This commit extends `ObligationCauseCode::WellFormed` to support recording a function parameter, allowing us to get the corresponding HIR type if an error occurs. Function typechecking is modified to pass this information during signature normalization and WF checking. The resulting code is fairly verbose, due to the fact that we can no longer normalize the entire signature with a single function call. As part of the refactoring, we now perform HIR-based WF checking for several other 'typed items' (statics, consts, and inherent impls). As a result, WF and projection errors in a function signature now have a precise span, which points directly at the responsible type. If a function signature is constructed via a macro, this will allow the error message to point at the code 'most responsible' for the error (e.g. a user-supplied macro argument). --- compiler/rustc_middle/src/hir/map/mod.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 34 +++++-- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_query_impl/src/keys.rs | 4 +- .../src/traits/error_reporting/mod.rs | 4 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 5 +- compiler/rustc_typeck/src/check/wfcheck.rs | 72 +++++++++++++-- compiler/rustc_typeck/src/hir_wf_check.rs | 91 ++++++++++++++----- .../associated-types-for-unimpl-trait.stderr | 7 +- .../associated-types-no-suitable-bound.stderr | 7 +- ...ated-types-no-suitable-supertrait-2.stderr | 7 +- ...ciated-types-no-suitable-supertrait.stderr | 14 ++- ...ted-trait-in-method-without-default.stderr | 7 +- .../object-safety-err-ret.stderr | 4 +- src/test/ui/error-codes/E0038.stderr | 4 +- ...ature-gate-object_safe_for_dispatch.stderr | 8 +- .../gat-in-trait-path.stderr | 4 +- .../issue-67510-pass.stderr | 4 +- .../trait-objects.stderr | 4 +- src/test/ui/issues/issue-18611.stderr | 7 +- src/test/ui/issues/issue-18959.stderr | 4 +- ...object-unsafe-trait-references-self.stderr | 8 +- ...unsafe-trait-should-use-where-sized.stderr | 4 +- src/test/ui/wf/wf-foreign-fn-decl-ret.stderr | 7 +- src/test/ui/wf/wf-in-fn-arg.stderr | 4 +- src/test/ui/wf/wf-trait-default-fn-arg.stderr | 4 +- src/test/ui/wf/wf-trait-fn-arg.stderr | 4 +- 28 files changed, 240 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index ae53f1ac3bb49..392372fad531e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -29,7 +29,10 @@ fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> { Node::Item(Item { kind: ItemKind::Fn(sig, _, _), .. }) | Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, _), .. }) => Some(&sig.decl), - Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) => Some(fn_decl), + Node::Expr(Expr { kind: ExprKind::Closure(_, fn_decl, ..), .. }) + | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, ..), .. }) => { + Some(fn_decl) + } _ => None, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index cb99ae19ee72e..0908b6a1763d5 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1722,7 +1722,7 @@ rustc_queries! { /// span) for an *existing* error. Therefore, it is best-effort, and may never handle /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine, /// because the `ty::Ty`-based wfcheck is always run. - query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, hir::HirId)) -> Option> { + query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option> { eval_always no_hash desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index f951e43fbfa35..a4a2e82463757 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -16,7 +16,7 @@ use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Constness; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -327,17 +327,39 @@ pub enum ObligationCauseCode<'tcx> { /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` OpaqueType, - /// Well-formed checking. If a `HirId` is provided, - /// it is used to perform HIR-based wf checking if an error - /// occurs, in order to generate a more precise error message. + /// Well-formed checking. If a `WellFormedLoc` is provided, + /// then it will be used to eprform HIR-based wf checking + /// after an error occurs, in order to generate a more precise error span. /// This is purely for diagnostic purposes - it is always - /// correct to use `MiscObligation` instead - WellFormed(Option), + /// correct to use `MiscObligation` instead, or to specify + /// `WellFormed(None)` + WellFormed(Option), /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against. MatchImpl(Lrc>, DefId), } +/// The 'location' at which we try to perform HIR-based wf checking. +/// This information is used to obtain an `hir::Ty`, which +/// we can walk in order to obtain precise spans for any +/// 'nested' types (e.g. `Foo` in `Option`). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] +pub enum WellFormedLoc { + /// Use the type of the provided definition. + Ty(LocalDefId), + /// Use the type of the parameter of the provided function. + /// We cannot use `hir::Param`, since the function may + /// not have a body (e.g. a trait method definition) + Param { + /// The function to lookup the parameter in + function: LocalDefId, + /// The index of the parameter to use. + /// Parameters are indexed from 0, with the return type + /// being the last 'parameter' + param_idx: u16, + }, +} + impl ObligationCauseCode<'_> { // Return the base obligation, ignoring derived obligations. pub fn peel_derives(&self) -> &Self { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b84058011066f..4ce49032398bc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1682,7 +1682,7 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} -CloneLiftImpls! { for<'tcx> { Constness, } } +CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index 1993e0a602fa5..0ad360c7d89c3 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -1,9 +1,9 @@ //! Defines the set of legal keys that can be used in queries. use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use rustc_hir::HirId; use rustc_middle::infer::canonical::Canonical; use rustc_middle::mir; +use rustc_middle::traits; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -397,7 +397,7 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { } } -impl<'tcx> Key for (ty::Predicate<'tcx>, HirId) { +impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { #[inline(always)] fn query_crate_is_local(&self) -> bool { true diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 5c4aef529e5ac..13a6733fb478a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -242,11 +242,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { SelectionError::Unimplemented => { // If this obligation was generated as a result of well-formed checking, see if we // can get a better error message by performing HIR-based well formed checking. - if let ObligationCauseCode::WellFormed(Some(wf_hir_id)) = + if let ObligationCauseCode::WellFormed(Some(wf_loc)) = root_obligation.cause.code.peel_derives() { if let Some(cause) = - self.tcx.diagnostic_hir_wf_check((obligation.predicate, *wf_hir_id)) + self.tcx.diagnostic_hir_wf_check((obligation.predicate, wf_loc.clone())) { obligation.cause = cause; span = obligation.cause.span; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 4ed07ba358de3..865e4ccc0b63f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -40,6 +40,7 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt, + WellFormedLoc, }; use std::collections::hash_map::Entry; @@ -419,13 +420,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, value: T, - hir_id: hir::HirId, + loc: WellFormedLoc, ) -> T where T: TypeFoldable<'tcx>, { self.inh.normalize_associated_types_in_with_cause( - ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(hir_id))), + ObligationCause::new(span, self.body_id, ObligationCauseCode::WellFormed(Some(loc))), self.param_env, value, ) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b24d63917c1cf..98980c65bc815 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -22,8 +22,9 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; +use std::convert::TryInto; use std::iter; use std::ops::ControlFlow; @@ -386,7 +387,7 @@ fn check_associated_item( span: Span, sig_if_method: Option<&hir::FnSig<'_>>, ) { - let code = ObligationCauseCode::WellFormed(Some(item_id)); + let code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))); for_id(tcx, item_id, span).with_fcx(|fcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id)); @@ -400,7 +401,11 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); + let ty = fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { @@ -422,7 +427,11 @@ fn check_associated_item( } if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); - let ty = fcx.normalize_associated_types_in_wf(span, ty, item_id); + let ty = fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); fcx.register_wf_obligation(ty.into(), span, code.clone()); } } @@ -621,7 +630,11 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo for_id(tcx, item_id, ty_span).with_fcx(|fcx| { let ty = tcx.type_of(tcx.hir().local_def_id(item_id)); - let item_ty = fcx.normalize_associated_types_in_wf(ty_span, ty, item_id); + let item_ty = fcx.normalize_associated_types_in_wf( + ty_span, + ty, + WellFormedLoc::Ty(item_id.expect_owner()), + ); let mut forbid_unsized = true; if allow_foreign_ty { @@ -634,7 +647,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo fcx.register_wf_obligation( item_ty.into(), ty_span, - ObligationCauseCode::WellFormed(Some(item_id)), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(item_id.expect_owner()))), ); if forbid_unsized { fcx.register_bound( @@ -684,7 +697,9 @@ fn check_impl<'tcx>( fcx.register_wf_obligation( self_ty.into(), ast_self_ty.span, - ObligationCauseCode::WellFormed(Some(item.hir_id())), + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty( + item.hir_id().expect_owner(), + ))), ); } } @@ -901,11 +916,48 @@ fn check_fn_or_method<'fcx, 'tcx>( implied_bounds: &mut Vec>, ) { let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); - let sig = fcx.normalize_associated_types_in(span, sig); - for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) { - fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::WellFormed(None)); + // Normalize the input and output types one at a time, using a different + // `WellFormedLoc` for each. We cannot call `normalize_associated_types` + // on the entire `FnSig`, since this would use the same `WellFormedLoc` + // for each type, preventing the HIR wf check from generating + // a nice error message. + let ty::FnSig { mut inputs_and_output, c_variadic, unsafety, abi } = sig; + inputs_and_output = + fcx.tcx.mk_type_list(inputs_and_output.iter().enumerate().map(|(i, ty)| { + fcx.normalize_associated_types_in_wf( + span, + ty, + WellFormedLoc::Param { + function: def_id.expect_local(), + // Note that the `param_idx` of the output type is + // one greater than the index of the last input type. + param_idx: i.try_into().unwrap(), + }, + ) + })); + // Manually call `normalize_assocaited_types_in` on the other types + // in `FnSig`. This ensures that if the types of these fields + // ever change to include projections, we will start normalizing + // them automatically. + let sig = ty::FnSig { + inputs_and_output, + c_variadic: fcx.normalize_associated_types_in(span, c_variadic), + unsafety: fcx.normalize_associated_types_in(span, unsafety), + abi: fcx.normalize_associated_types_in(span, abi), + }; + + for (i, (&input_ty, ty)) in iter::zip(sig.inputs(), hir_decl.inputs).enumerate() { + fcx.register_wf_obligation( + input_ty.into(), + ty.span, + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param { + function: def_id.expect_local(), + param_idx: i.try_into().unwrap(), + })), + ); } + implied_bounds.extend(sig.inputs()); fcx.register_wf_obligation( diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index a8ec7b79e571f..c1af10f5ce451 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -3,10 +3,10 @@ use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::HirId; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::ObligationCause; use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, ToPredicate, TyCtxt}; +use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder}; use rustc_trait_selection::traits; pub fn provide(providers: &mut Providers) { @@ -17,21 +17,20 @@ pub fn provide(providers: &mut Providers) { // need access to `ItemCtxt` fn diagnostic_hir_wf_check<'tcx>( tcx: TyCtxt<'tcx>, - (predicate, hir_id): (ty::Predicate<'tcx>, HirId), + (predicate, loc): (ty::Predicate<'tcx>, WellFormedLoc), ) -> Option> { let hir = tcx.hir(); - // HIR wfcheck should only ever happen as part of improving an existing error - tcx.sess.delay_span_bug(hir.span(hir_id), "Performed HIR wfcheck without an existing error!"); - // Currently, we only handle WF checking for items (e.g. associated items). - // It would be nice to extend this to handle wf checks inside functions. - let def_id = match tcx.hir().opt_local_def_id(hir_id) { - Some(def_id) => def_id, - None => return None, + let def_id = match loc { + WellFormedLoc::Ty(def_id) => def_id, + WellFormedLoc::Param { function, param_idx: _ } => function, }; + let hir_id = HirId::make_owner(def_id); + + // HIR wfcheck should only ever happen as part of improving an existing error + tcx.sess + .delay_span_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!"); - // FIXME - figure out how we want to handle wf-checking for - // things inside a function body. let icx = ItemCtxt::new(tcx, def_id.to_def_id()); // To perform HIR-based WF checking, we iterate over all HIR types @@ -72,7 +71,8 @@ fn diagnostic_hir_wf_check<'tcx>( fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { self.tcx.infer_ctxt().enter(|infcx| { let mut fulfill = traits::FulfillmentContext::new(); - let tcx_ty = self.icx.to_ty(ty); + let tcx_ty = + self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( ty.span, self.hir_id, @@ -119,19 +119,66 @@ fn diagnostic_hir_wf_check<'tcx>( depth: 0, }; - let ty = match tcx.hir().get(hir_id) { - hir::Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::TyAlias(ty) => Some(ty), - _ => None, - }, - hir::Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Type(_, ty) => ty, - _ => None, + // Get the starting `hir::Ty` using our `WellFormedLoc`. + // We will walk 'into' this type to try to find + // a more precise span for our predicate. + let ty = match loc { + WellFormedLoc::Ty(_) => match hir.get(hir_id) { + hir::Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::TyAlias(ty) => Some(ty), + ref item => bug!("Unexpected ImplItem {:?}", item), + }, + hir::Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Type(_, ty) => ty, + ref item => bug!("Unexpected TraitItem {:?}", item), + }, + hir::Node::Item(item) => match item.kind { + hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _) => Some(ty), + hir::ItemKind::Impl(ref impl_) => { + assert!(impl_.of_trait.is_none(), "Unexpected trait impl: {:?}", impl_); + Some(impl_.self_ty) + } + ref item => bug!("Unexpected item {:?}", item), + }, + ref node => bug!("Unexpected node {:?}", node), }, - _ => None, + WellFormedLoc::Param { function: _, param_idx } => { + let fn_decl = hir.fn_decl_by_hir_id(hir_id).unwrap(); + // Get return type + if param_idx as usize == fn_decl.inputs.len() { + match fn_decl.output { + hir::FnRetTy::Return(ty) => Some(ty), + // The unit type `()` is always well-formed + hir::FnRetTy::DefaultReturn(_span) => None, + } + } else { + Some(&fn_decl.inputs[param_idx as usize]) + } + } }; if let Some(ty) = ty { visitor.visit_ty(ty); } visitor.cause } + +struct EraseAllBoundRegions<'tcx> { + tcx: TyCtxt<'tcx>, +} + +// Higher ranked regions are complicated. +// To make matters worse, the HIR WF check can instantiate them +// outside of a `Binder`, due to the way we (ab)use +// `ItemCtxt::to_ty`. To make things simpler, we just erase all +// of them, regardless of depth. At worse, this will give +// us an inaccurate span for an error message, but cannot +// lead to unsoundess (we call `delay_span_bug` at the start +// of `diagnostic_hir_wf_check`). +impl<'tcx> TypeFolder<'tcx> for EraseAllBoundRegions<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { + if let ty::ReLateBound(..) = r { &ty::ReErased } else { r } + } +} diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr index e8c11a32bf7fd..25e80159b0b18 100644 --- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr +++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-for-unimpl-trait.rs:10:8 + --> $DIR/associated-types-for-unimpl-trait.rs:10:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr index e3be434698ab9..19500f58aa688 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `T: Get` is not satisfied - --> $DIR/associated-types-no-suitable-bound.rs:11:8 + --> $DIR/associated-types-no-suitable-bound.rs:11:21 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(foo: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr index 9dc3414e9edf0..0e978f20a6634 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:8 + --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr index c2aed3f9de548..1ec3c05983aef 100644 --- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:17:8 + --> $DIR/associated-types-no-suitable-supertrait.rs:17:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: ::Value) {} - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | @@ -10,10 +13,13 @@ LL | fn uhoh(&self, foo: U, bar: ::Value) where Self: Ge | ^^^^^^^^^^^^^^^ error[E0277]: the trait bound `(T, U): Get` is not satisfied - --> $DIR/associated-types-no-suitable-supertrait.rs:22:8 + --> $DIR/associated-types-no-suitable-supertrait.rs:22:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} - | ^^^^ the trait `Get` is not implemented for `(T, U)` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr index fb842d968676d..b6ee1ed733c3e 100644 --- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr +++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `Self: Get` is not satisfied - --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:8 + --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:40 | +LL | trait Get { + | --------- required by this bound in `Get` +... LL | fn okay(&self, foo: U, bar: ::Value); - | ^^^^ the trait `Get` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr index e0e6029252c00..319e6c2c032a0 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/object-safety-err-ret.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-ret.rs:17:15 + --> $DIR/object-safety-err-ret.rs:17:16 | LL | fn use_dyn(v: &dyn Foo) { - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` cannot be made into an object | = help: consider moving `test` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/error-codes/E0038.stderr b/src/test/ui/error-codes/E0038.stderr index eb68a6298d1ac..cead9776e4abb 100644 --- a/src/test/ui/error-codes/E0038.stderr +++ b/src/test/ui/error-codes/E0038.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/E0038.rs:5:16 + --> $DIR/E0038.rs:5:20 | LL | fn call_foo(x: Box) { - | ^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr index 12195bc1071a0..c13c05f146a7e 100644 --- a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr +++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `NonObjectSafe1` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:38 + --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:39 | LL | fn takes_non_object_safe_ref(obj: &dyn NonObjectSafe1) { - | ^^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe1` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/feature-gate-object_safe_for_dispatch.rs:4:23 @@ -35,10 +35,10 @@ LL | fn static_fn() where Self: Sized {} | ^^^^^^^^^^^^^^^^^ error[E0038]: the trait `NonObjectSafe3` cannot be made into an object - --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:35 + --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:39 | LL | fn takes_non_object_safe_box(obj: Box) { - | ^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^ `NonObjectSafe3` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr index eb8e101a83d79..8651789688eaa 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/gat-in-trait-path.rs:21:13 + --> $DIR/gat-in-trait-path.rs:21:17 | LL | fn f(_arg : Box Foo = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | = help: consider moving `A` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.stderr index 8cc9f2816a166..b4b89ab047363 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.stderr +++ b/src/test/ui/generic-associated-types/issue-67510-pass.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `X` cannot be made into an object - --> $DIR/issue-67510-pass.rs:7:19 + --> $DIR/issue-67510-pass.rs:7:23 | LL | fn _func1<'a>(_x: Box=&'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | = help: consider moving `Y` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/generic-associated-types/trait-objects.stderr b/src/test/ui/generic-associated-types/trait-objects.stderr index a121566bbd884..6429bb8159e1f 100644 --- a/src/test/ui/generic-associated-types/trait-objects.stderr +++ b/src/test/ui/generic-associated-types/trait-objects.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `StreamingIterator` cannot be made into an object - --> $DIR/trait-objects.rs:10:16 + --> $DIR/trait-objects.rs:10:21 | LL | fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object | = help: consider moving `Item` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/issues/issue-18611.stderr b/src/test/ui/issues/issue-18611.stderr index 8872f51753c94..0e942e80e2544 100644 --- a/src/test/ui/issues/issue-18611.stderr +++ b/src/test/ui/issues/issue-18611.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `isize: HasState` is not satisfied - --> $DIR/issue-18611.rs:1:4 + --> $DIR/issue-18611.rs:1:18 | LL | fn add_state(op: ::State) { - | ^^^^^^^^^ the trait `HasState` is not implemented for `isize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasState` is not implemented for `isize` +... +LL | trait HasState { + | -------------- required by this bound in `HasState` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18959.stderr b/src/test/ui/issues/issue-18959.stderr index 86b530e85a80a..2a5416ce85ba6 100644 --- a/src/test/ui/issues/issue-18959.stderr +++ b/src/test/ui/issues/issue-18959.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-18959.rs:11:11 + --> $DIR/issue-18959.rs:11:12 | LL | fn foo(b: &dyn Bar) { - | ^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` cannot be made into an object | = help: consider moving `foo` to another trait note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit diff --git a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr index 797406f869fe6..f332b7213d8bc 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-references-self.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:6:11 + --> $DIR/object-unsafe-trait-references-self.rs:6:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | = help: consider moving `baz` to another trait = help: consider moving `bat` to another trait @@ -17,10 +17,10 @@ LL | fn bat(&self) -> Self {} | ^^^^ ...because method `bat` references the `Self` type in its return type error[E0038]: the trait `Other` cannot be made into an object - --> $DIR/object-unsafe-trait-references-self.rs:10:11 + --> $DIR/object-unsafe-trait-references-self.rs:10:12 | LL | fn foo(x: &dyn Other) {} - | ^^^^^^^^^^ `Other` cannot be made into an object + | ^^^^^^^^^ `Other` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-references-self.rs:8:14 diff --git a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr index a2caf846cc5fe..4c18f6d79d077 100644 --- a/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr +++ b/src/test/ui/suggestions/object-unsafe-trait-should-use-where-sized.stderr @@ -1,8 +1,8 @@ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:11 + --> $DIR/object-unsafe-trait-should-use-where-sized.rs:9:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/object-unsafe-trait-should-use-where-sized.rs:5:8 diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr index a0eb7d10bd94a..f6b48938f9b04 100644 --- a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr +++ b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/wf-foreign-fn-decl-ret.rs:11:12 + --> $DIR/wf-foreign-fn-decl-ret.rs:11:25 | +LL | pub trait Foo { + | ------------- required by this bound in `Foo` +... LL | pub fn lint_me() -> <() as Foo>::Assoc; - | ^^^^^^^ the trait `Foo` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied --> $DIR/wf-foreign-fn-decl-ret.rs:14:32 diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index 9687658feba43..ca90e9222dea9 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/wf-in-fn-arg.rs:10:14 + --> $DIR/wf-in-fn-arg.rs:10:15 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | fn bar(_: &MustBeCopy) - | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index c3d5d2b9669b8..2a129538f7633 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-default-fn-arg.rs:11:22 + --> $DIR/wf-trait-default-fn-arg.rs:11:23 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar) { - | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr index 4510f50feea58..7693aa6d2d583 100644 --- a/src/test/ui/wf/wf-trait-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-fn-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-fn-arg.rs:10:22 + --> $DIR/wf-trait-fn-arg.rs:10:23 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar); - | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` |