diff options
Diffstat (limited to 'compiler/rustc_trait_selection')
36 files changed, 746 insertions, 488 deletions
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index b13a753c4ed..1c61e23362a 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -1,14 +1,13 @@ [package] name = "rustc_trait_selection" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 055a3edcc32..4db9d9915b1 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -225,14 +225,6 @@ trait_selection_mismatched_static_lifetime = incompatible lifetime on type trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute .help = at least one of the `message`, `note` and `label` options are expected -trait_selection_more_targeted = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but calling `{$ident}` introduces an implicit `'static` lifetime requirement - trait_selection_msl_introduces_static = introduces a `'static` lifetime requirement trait_selection_msl_unmet_req = because this has an unmet lifetime requirement diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 091773009e9..a618bae269f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1989,7 +1989,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trace: &TypeTrace<'tcx>, span: Span, ) -> Option<TypeErrorAdditionalDiags> { - let hir = self.tcx.hir(); let TypeError::ArraySize(sz) = terr else { return None; }; @@ -1997,7 +1996,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { body: body_id, .. }, .. }) => { - let body = hir.body(*body_id); + let body = self.tcx.hir_body(*body_id); struct LetVisitor { span: Span, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 99b70c87ccd..bed9734f389 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -18,6 +18,7 @@ use rustc_middle::ty::{ TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, }; use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym}; +use rustc_type_ir::visit::TypeVisitableExt; use tracing::{debug, instrument, warn}; use super::nice_region_error::placeholder_error::Highlighted; @@ -155,27 +156,92 @@ impl UnderspecifiedArgKind { } } -struct ClosureEraser<'tcx> { - tcx: TyCtxt<'tcx>, +struct ClosureEraser<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, } -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> { +impl<'a, 'tcx> ClosureEraser<'a, 'tcx> { + fn new_infer(&mut self) -> Ty<'tcx> { + self.infcx.next_ty_var(DUMMY_SP) + } +} + +impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'a, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.tcx + self.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { match ty.kind() { ty::Closure(_, args) => { + // For a closure type, we turn it into a function pointer so that it gets rendered + // as `fn(args) -> Ret`. let closure_sig = args.as_closure().sig(); Ty::new_fn_ptr( - self.tcx, - self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe), + self.cx(), + self.cx().signature_unclosure(closure_sig, hir::Safety::Safe), ) } - _ => ty.super_fold_with(self), + ty::Adt(_, args) if !args.iter().any(|a| a.has_infer()) => { + // We have a type that doesn't have any inference variables, so we replace + // the whole thing with `_`. The type system already knows about this type in + // its entirety and it is redundant to specify it for the user. The user only + // needs to specify the type parameters that we *couldn't* figure out. + self.new_infer() + } + ty::Adt(def, args) => { + let generics = self.cx().generics_of(def.did()); + let generics: Vec<bool> = generics + .own_params + .iter() + .map(|param| param.default_value(self.cx()).is_some()) + .collect(); + let ty = Ty::new_adt( + self.cx(), + *def, + self.cx().mk_args_from_iter(generics.into_iter().zip(args.iter()).map( + |(has_default, arg)| { + if arg.has_infer() { + // This param has an unsubstituted type variable, meaning that this + // type has a (potentially deeply nested) type parameter from the + // corresponding type's definition. We have explicitly asked this + // type to not be hidden. In either case, we keep the type and don't + // substitute with `_` just yet. + arg.fold_with(self) + } else if has_default { + // We have a type param that has a default type, like the allocator + // in Vec. We decided to show `Vec` itself, because it hasn't yet + // been replaced by an `_` `Infer`, but we want to ensure that the + // type parameter with default types does *not* get replaced with + // `_` because then we'd end up with `Vec<_, _>`, instead of + // `Vec<_>`. + arg + } else if let GenericArgKind::Type(_) = arg.unpack() { + // We don't replace lifetime or const params, only type params. + self.new_infer().into() + } else { + arg.fold_with(self) + } + }, + )), + ); + ty + } + _ if ty.has_infer() => { + // This type has a (potentially nested) type parameter that we couldn't figure out. + // We will print this depth of type, so at least the type name and at least one of + // its type parameters. + ty.super_fold_with(self) + } + // We don't have an unknown type parameter anywhere, replace with `_`. + _ => self.new_infer(), } } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + // Avoid accidentally erasing the type of the const. + c + } } fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> { @@ -219,9 +285,9 @@ fn ty_to_string<'tcx>( ) -> String { let mut printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); - // We use `fn` ptr syntax for closures, but this only works when the closure - // does not capture anything. - let ty = ty.fold_with(&mut ClosureEraser { tcx: infcx.tcx }); + // We use `fn` ptr syntax for closures, but this only works when the closure does not capture + // anything. We also remove all type parameters that are fully known to the type system. + let ty = ty.fold_with(&mut ClosureEraser { infcx }); match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in @@ -422,7 +488,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg); - if let Some(body) = self.tcx.hir().maybe_body_owned_by( + if let Some(body) = self.tcx.hir_maybe_body_owned_by( self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(), ) { let expr = body.value; @@ -1008,7 +1074,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { &self, path: &'tcx hir::Path<'tcx>, args: GenericArgsRef<'tcx>, - ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a { + ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'tcx { let tcx = self.tecx.tcx; let have_turbofish = path.segments.iter().any(|segment| { segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const())) @@ -1135,8 +1201,8 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> Self::Map { - self.tecx.tcx.hir() + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tecx.tcx } fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { @@ -1253,7 +1319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { { let output = args.as_closure().sig().output().skip_binder(); if self.generic_arg_contains_target(output.into()) { - let body = self.tecx.tcx.hir().body(body); + let body = self.tecx.tcx.hir_body(body); let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) { None } else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index b9f3abc2534..5a303c3cd03 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -3,7 +3,6 @@ use core::ops::ControlFlow; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; use rustc_hir::{self as hir, AmbigArg}; -use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::{self, Region, TyCtxt}; @@ -70,8 +69,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { type Result = ControlFlow<&'tcx hir::Ty<'tcx>>; type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx } fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result { @@ -176,8 +175,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { type Result = ControlFlow<()>; type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> Map<'tcx> { - self.tcx.hir() + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx } fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> Self::Result { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs index 886581bc35f..0904177ea8b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs @@ -33,11 +33,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }; // If we added a "points at argument expression" obligation, we remove it here, we care // about the original obligation only. - let code = match cause.code() { - ObligationCauseCode::FunctionArg { parent_code, .. } => &*parent_code, - code => code, - }; - let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else { + let ObligationCauseCode::MatchImpl(parent, impl_def_id) = cause.code() else { return None; }; let (ObligationCauseCode::WhereClause(_, binding_span) @@ -66,7 +62,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); let mut impl_span = None; let mut implicit_static_lifetimes = Vec::new(); - if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) { + if let Some(impl_node) = self.tcx().hir_get_if_local(*impl_def_id) { // If an impl is local, then maybe this isn't what they want. Try to // be as helpful as possible with implicit lifetimes. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 039e21cb556..083ce022238 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -1,27 +1,21 @@ //! Error Reporting for static impl Traits. use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; use rustc_hir::{ self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, }; -use rustc_middle::ty::{ - self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, -}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; use rustc_span::{Ident, Span}; use tracing::debug; use crate::error_reporting::infer::nice_region_error::NiceRegionError; -use crate::errors::{ - ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted, - ReqIntroducedLocations, -}; -use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace}; -use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; +use crate::errors::ButNeedsToSatisfy; +use crate::infer::{RegionResolutionError, SubregionOrigin}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static `impl Trait`, @@ -39,52 +33,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sup_r, spans, ) if sub_r.is_static() => (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans), - RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { cause, .. }), - sub_r, - sup_r, - ) if sub_r.is_static() => { - // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. - if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() { - // This may have a closure and it would cause ICE - // through `find_param_with_region` (#78262). - let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?; - let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.scope); - if fn_returns.is_empty() { - return None; - } - - let param = self.find_param_with_region(*sup_r, *sub_r)?; - let simple_ident = param.param.pat.simple_ident(); - - let (has_impl_path, impl_path) = match ctxt.assoc_item.container { - AssocItemContainer::Trait => { - let id = ctxt.assoc_item.container_id(tcx); - (true, tcx.def_path_str(id)) - } - AssocItemContainer::Impl => (false, String::new()), - }; - - let mut err = self.tcx().dcx().create_err(ButCallingIntroduces { - param_ty_span: param.param_ty_span, - cause_span: cause.span, - has_param_name: simple_ident.is_some(), - param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), - has_lifetime: sup_r.has_name(), - lifetime: sup_r.to_string(), - assoc_item: ctxt.assoc_item.name, - has_impl_path, - impl_path, - }); - if self.find_impl_on_dyn_trait(&mut err, param.param_ty, ctxt) { - let reported = err.emit(); - return Some(reported); - } else { - err.cancel() - } - } - return None; - } _ => return None, }; debug!( @@ -140,39 +88,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { None }; - let mut subdiag = None; - - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { - if let ObligationCauseCode::ReturnValue(hir_id) - | ObligationCauseCode::BlockTailExpression(hir_id, ..) = cause.code() - { - let parent_id = tcx.hir().get_parent_item(*hir_id); - if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) { - let mut span: MultiSpan = fn_decl.output.span().into(); - let mut spans = Vec::new(); - let mut add_label = true; - if let hir::FnRetTy::Return(ty) = fn_decl.output { - let mut v = StaticLifetimeVisitor(vec![], tcx.hir()); - v.visit_ty_unambig(ty); - if !v.0.is_empty() { - span = v.0.clone().into(); - spans = v.0; - add_label = false; - } - } - let fn_decl_span = fn_decl.output.span(); - - subdiag = Some(ReqIntroducedLocations { - span, - spans, - fn_decl_span, - cause_span: cause.span, - add_label, - }); - } - } - } - let diag = ButNeedsToSatisfy { sp, influencer_point, @@ -183,7 +98,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { require_span_as_note: require_as_note.then_some(require_span), // We don't need a note, it's already at the end, it can be shown as a `span_label`. require_span_as_label: (!require_as_note).then_some(require_span), - req_introduces_loc: subdiag, has_lifetime: sup_r.has_name(), lifetime: lifetime_name.clone(), @@ -197,45 +111,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.scope); - let mut override_error_code = None; - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin - && let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() - // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a - // `'static` lifetime when called as a method on a binding: `bar.qux()`. - && self.find_impl_on_dyn_trait(&mut err, param.param_ty, ctxt) - { - override_error_code = Some(ctxt.assoc_item.name); - } - - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin - && let code = match cause.code() { - ObligationCauseCode::MatchImpl(parent, ..) => parent.code(), - _ => cause.code(), - } - && let ( - &ObligationCauseCode::WhereClause(item_def_id, _) - | &ObligationCauseCode::WhereClauseInExpr(item_def_id, ..), - None, - ) = (code, override_error_code) - { - // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static` - // lifetime as above, but called using a fully-qualified path to the method: - // `Foo::qux(bar)`. - let mut v = TraitObjectVisitor(FxIndexSet::default()); - v.visit_ty(param.param_ty); - if let Some((ident, self_ty)) = - NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0) - && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) - { - override_error_code = Some(ident.name); - } - } - if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { - // Provide a more targeted error code and description. - let retarget_subdiag = MoreTargeted { ident }; - retarget_subdiag.add_to_diag(&mut err); - } - let arg = match param.param.pat.simple_ident() { Some(simple_ident) => format!("argument `{simple_ident}`"), None => "the argument".to_string(), @@ -318,7 +193,7 @@ pub fn suggest_new_region_bound( } else { // get a lifetime name of existing named lifetimes if any let existing_lt_name = if let Some(id) = scope_def_id - && let Some(generics) = tcx.hir().get_generics(id) + && let Some(generics) = tcx.hir_get_generics(id) && let named_lifetimes = generics .params .iter() @@ -349,7 +224,7 @@ pub fn suggest_new_region_bound( // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used. // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any if let Some(id) = scope_def_id - && let Some(generics) = tcx.hir().get_generics(id) + && let Some(generics) = tcx.hir_get_generics(id) && let mut spans_suggs = make_elided_region_spans_suggs(name, generics.params.iter()) && spans_suggs.len() > 1 @@ -470,9 +345,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { def_id: DefId, trait_objects: &FxIndexSet<DefId>, ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> { - match tcx.hir().get_if_local(def_id)? { + match tcx.hir_get_if_local(def_id)? { Node::ImplItem(impl_item) => { - let impl_did = tcx.hir().get_parent_item(impl_item.hir_id()); + let impl_did = tcx.hir_get_parent_item(impl_item.hir_id()); if let hir::OwnerNode::Item(Item { kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. @@ -484,19 +359,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } Node::TraitItem(trait_item) => { - let trait_id = tcx.hir().get_parent_item(trait_item.hir_id()); + let trait_id = tcx.hir_get_parent_item(trait_item.hir_id()); debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait); // The method being called is defined in the `trait`, but the `'static` // obligation comes from the `impl`. Find that `impl` so that we can point // at it in the suggestion. let trait_did = trait_id.to_def_id(); - tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| { + tcx.hir_trait_impls(trait_did).iter().find_map(|&impl_did| { if let Node::Item(Item { kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. }) = tcx.hir_node_by_def_id(impl_did) && trait_objects.iter().all(|did| { - // FIXME: we should check `self_ty` against the receiver - // type in the `UnifyReceiver` context, but for now, use + // FIXME: we should check `self_ty`, but for now, use // this imperfect proxy. This will fail if there are // multiple `impl`s for the same trait like // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`. @@ -516,62 +390,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _ => None, } } - - /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default - /// `'static` obligation. Suggest relaxing that implicit bound. - fn find_impl_on_dyn_trait( - &self, - err: &mut Diag<'_>, - ty: Ty<'_>, - ctxt: &UnifyReceiverContext<'tcx>, - ) -> bool { - let tcx = self.tcx(); - - // Find the method being called. - let Ok(Some(instance)) = ty::Instance::try_resolve( - tcx, - self.cx.typing_env(ctxt.param_env), - ctxt.assoc_item.def_id, - self.cx.resolve_vars_if_possible(ctxt.args), - ) else { - return false; - }; - - let mut v = TraitObjectVisitor(FxIndexSet::default()); - v.visit_ty(ty); - - // Get the `Ident` of the method being called and the corresponding `impl` (to point at - // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). - let Some((ident, self_ty)) = - NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) - else { - return false; - }; - - // Find the trait object types in the argument, so we point at *only* the trait object. - self.suggest_constrain_dyn_trait_in_impl(err, &v.0, ident, self_ty) - } - - fn suggest_constrain_dyn_trait_in_impl( - &self, - err: &mut Diag<'_>, - found_dids: &FxIndexSet<DefId>, - ident: Ident, - self_ty: &hir::Ty<'_>, - ) -> bool { - let mut suggested = false; - for found_did in found_dids { - let mut traits = vec![]; - let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did); - hir_v.visit_ty_unambig(self_ty); - for &span in &traits { - let subdiag = DynTraitConstraintSuggestion { span, ident }; - subdiag.add_to_diag(err); - suggested = true; - } - } - suggested - } } /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index bbcd28c0835..cc2ab1c3432 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -99,11 +99,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; match assoc_item.kind { ty::AssocKind::Fn => { - let hir = self.tcx().hir(); if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id)) { - if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) { + if let Some(decl) = self.tcx().hir_fn_decl_by_hir_id(hir_id) { visitor.visit_fn_decl(decl); } } @@ -133,8 +132,8 @@ struct TypeParamSpanVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { type NestedFilter = nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx } fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 445937ad169..245764c94ab 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -64,10 +64,10 @@ pub fn find_param_with_region<'tcx>( _ => {} } - let body = hir.maybe_body_owned_by(def_id)?; + let body = tcx.hir_maybe_body_owned_by(def_id)?; - let owner_id = hir.body_owner(body.id()); - let fn_decl = hir.fn_decl_by_hir_id(owner_id)?; + let owner_id = tcx.hir_body_owner(body.id()); + let fn_decl = tcx.hir_fn_decl_by_hir_id(owner_id)?; let poly_fn_sig = tcx.fn_sig(id).instantiate_identity(); let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index e8d14b89d69..514615735a5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -522,7 +522,8 @@ impl<T> Trait<T> for X { } } TypeError::TargetFeatureCast(def_id) => { - let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); + let target_spans = + tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span()); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); @@ -543,7 +544,7 @@ impl<T> Trait<T> for X { let tcx = self.tcx; let assoc = tcx.associated_item(proj_ty.def_id); let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx); - let Some(item) = tcx.hir().get_if_local(body_owner_def_id) else { + let Some(item) = tcx.hir_get_if_local(body_owner_def_id) else { return false; }; let Some(hir_generics) = item.generics() else { @@ -586,7 +587,7 @@ impl<T> Trait<T> for X { hir::Node::TraitItem(item) => item.hir_id(), _ => return false, }; - let parent = tcx.hir().get_parent_item(hir_id).def_id; + let parent = tcx.hir_get_parent_item(hir_id).def_id; self.suggest_constraint(diag, msg, parent.into(), proj_ty, ty) } @@ -625,7 +626,7 @@ impl<T> Trait<T> for X { ) }; - let body_owner = tcx.hir().get_if_local(body_owner_def_id); + let body_owner = tcx.hir_get_if_local(body_owner_def_id); let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. @@ -820,7 +821,7 @@ fn foo(&self) -> Self::T { String::new() } // When `body_owner` is an `impl` or `trait` item, look in its associated types for // `expected` and point at it. let hir_id = tcx.local_def_id_to_hir_id(def_id); - let parent_id = tcx.hir().get_parent_item(hir_id); + let parent_id = tcx.hir_get_parent_item(hir_id); let item = tcx.hir_node_by_def_id(parent_id.def_id); debug!("expected_projection parent item {:?}", item); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index f35a5349ecb..fecb38ab597 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -2,7 +2,7 @@ use std::iter; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ - Applicability, Diag, E0309, E0310, E0311, E0495, Subdiagnostic, struct_span_code_err, + Applicability, Diag, E0309, E0310, E0311, E0803, Subdiagnostic, struct_span_code_err, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -487,7 +487,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &format!("`{sup}: {sub}`"), ); // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause - if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) + if let Some(generics) = self.tcx.hir_get_generics(impl_item_def_id) && generics.where_clause_span.contains(span) { self.suggest_copy_trait_method_bounds( @@ -590,7 +590,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return; }; - let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { + let Some(generics) = self.tcx.hir_get_generics(impl_item_def_id) else { return; }; @@ -763,7 +763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. - let hir_generics = self.tcx.hir().get_generics(scope).unwrap(); + let hir_generics = self.tcx.hir_get_generics(scope).unwrap(); let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) { Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)), // If `param` corresponds to `Self`, no usable suggestion span. @@ -822,7 +822,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { // The lifetime found in the `impl` is longer than the one on the RPITIT. // Do not suggest `<Type as Trait>::{opaque}: 'static`. - } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) { + } else if let Some(generics) = self.tcx.hir_get_generics(suggestion_scope) { let pred = format!("{bound_kind}: {lt_name}"); let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred); suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion)) @@ -907,7 +907,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::OwnerNode::Synthetic => unreachable!(), } - let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap(); + let ast_generics = self.tcx.hir_get_generics(lifetime_scope).unwrap(); let sugg = ast_generics .span_for_lifetime_suggestion() .map(|span| (span, format!("{new_lt}, "))) @@ -1032,7 +1032,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct_span_code_err!( self.dcx(), var_origin.span(), - E0495, + E0803, "cannot infer an appropriate lifetime{} due to conflicting requirements", var_description ) @@ -1382,7 +1382,7 @@ fn suggest_precise_capturing<'tcx>( new_params += name_as_bounds; } - let Some(generics) = tcx.hir().get_generics(fn_def_id) else { + let Some(generics) = tcx.hir_get_generics(fn_def_id) else { // This shouldn't happen, but don't ICE. return; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 562000e28ac..a7e68e6419d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -10,7 +10,6 @@ use rustc_hir::def::Res; use rustc_hir::{MatchSource, Node}; use rustc_middle::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, - StatementAsExpression, }; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -26,8 +25,14 @@ use crate::errors::{ SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags, }; +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +enum StatementAsExpression { + CorrectType, + NeedsBoxing, +} + #[derive(Clone, Copy)] -pub enum SuggestAsRefKind { +enum SuggestAsRefKind { Option, Result, } @@ -232,7 +237,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - ref prior_non_diverging_arms, + prior_non_diverging_arms, .. }) => Some({ ConsiderAddingAwait::FutureSuggMultiple { @@ -382,7 +387,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - pub fn suggest_function_pointers_impl( + pub(crate) fn suggest_function_pointers_impl( &self, span: Option<Span>, exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, @@ -518,7 +523,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - pub fn should_suggest_as_ref_kind( + fn should_suggest_as_ref_kind( &self, expected: Ty<'tcx>, found: Ty<'tcx>, @@ -588,8 +593,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) -> Option<TypeErrorAdditionalDiags> { /// Find the if expression with given span struct IfVisitor { - pub found_if: bool, - pub err_span: Span, + found_if: bool, + err_span: Span, } impl<'v> Visitor<'v> for IfVisitor { @@ -624,7 +629,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - self.tcx.hir().maybe_body_owned_by(cause.body_id).and_then(|body| { + self.tcx.hir_maybe_body_owned_by(cause.body_id).and_then(|body| { IfVisitor { err_span: span, found_if: false } .visit_body(&body) .is_break() @@ -649,7 +654,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { else { return; }; - let hir::Body { params, .. } = self.tcx.hir().body(*body); + let hir::Body { params, .. } = self.tcx.hir_body(*body); // 1. Get the args of the closure. // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1]. @@ -736,7 +741,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// Be helpful when the user wrote `{... expr; }` and taking the `;` off /// is enough to fix the error. - pub fn could_remove_semicolon( + fn could_remove_semicolon( &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, @@ -816,7 +821,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// Suggest returning a local binding with a compatible type if the block /// has no return expression. - pub fn consider_returning_binding_diag( + fn consider_returning_binding_diag( &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, @@ -846,7 +851,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { true }; - let hir = self.tcx.hir(); for stmt in blk.stmts.iter().rev() { let hir::StmtKind::Let(local) = &stmt.kind else { continue; @@ -871,7 +875,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { kind: hir::ExprKind::Closure(hir::Closure { body, .. }), .. }) => { - for param in hir.body(*body).params { + for param in self.tcx.hir_body(*body).params { param.pat.walk(&mut find_compatible_candidates); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 6beb108bc3a..f15f1b78b52 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -316,7 +316,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack()) - && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) + && let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) { let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(&body.value); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 1b43820bac0..596f794568c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -192,19 +192,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let have_alt_message = message.is_some() || label.is_some(); let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id()); + let is_question_mark = matches!( + root_obligation.cause.code().peel_derives(), + ObligationCauseCode::QuestionMark, + ) && !( + self.tcx.is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id()) + || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try) + ); let is_unsize = self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize); + let question_mark_message = "the question mark operation (`?`) implicitly \ + performs a conversion on the error value \ + using the `From` trait"; let (message, notes, append_const_msg) = if is_try_conversion { + // We have a `-> Result<_, E1>` and `gives_E2()?`. ( Some(format!( "`?` couldn't convert the error to `{}`", main_trait_predicate.skip_binder().self_ty(), )), - vec![ - "the question mark operation (`?`) implicitly performs a \ - conversion on the error value using the `From` trait" - .to_owned(), - ], + vec![question_mark_message.to_owned()], + Some(AppendConstMessage::Default), + ) + } else if is_question_mark { + // Similar to the case above, but in this case the conversion is for a + // trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when + // `E: Error` isn't met. + ( + Some(format!( + "`?` couldn't convert the error: `{main_trait_predicate}` is \ + not satisfied", + )), + vec![question_mark_message.to_owned()], Some(AppendConstMessage::Default), ) } else { @@ -220,8 +239,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &mut long_ty_file, ); - let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait) - { + let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item( + main_trait_predicate.def_id(), + LangItem::TransmuteTrait, + ) { // Recompute the safe transmute reason and use that for the error reporting match self.get_safe_transmute_error_and_reason( obligation.clone(), @@ -249,18 +270,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { *err.long_ty_path() = long_ty_file; let mut suggested = false; - if is_try_conversion { + if is_try_conversion || is_question_mark { suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); } - if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { - err.span_label( - ret_span, - format!( - "expected `{}` because of this", - main_trait_predicate.skip_binder().self_ty() - ), - ); + if let Some(ret_span) = self.return_type_span(&obligation) { + if is_try_conversion { + err.span_label( + ret_span, + format!( + "expected `{}` because of this", + main_trait_predicate.skip_binder().self_ty() + ), + ); + } else if is_question_mark { + err.span_label(ret_span, format!("required `{main_trait_predicate}` because of this")); + } } if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) { @@ -302,10 +327,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s); - if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) { + if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. + && !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id()) + // Don't say "the trait `FromResidual<Option<Infallible>>` is + // not implemented for `Result<T, E>`". + { err.help(explanation); } } else if let Some(custom_explanation) = safe_transmute_explanation { @@ -367,7 +396,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (span.shrink_to_lo(), format!("(")), (span.shrink_to_hi(), format!(" as {})", cand.self_ty())), ] - } else if let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { + } else if let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) { let mut expr_finder = FindExprBySpan::new(span, self.tcx); expr_finder.visit_expr(body.value); if let Some(expr) = expr_finder.result && @@ -585,6 +614,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { let ty = self.resolve_vars_if_possible(ty); if self.next_trait_solver() { + if let Err(guar) = ty.error_reported() { + return guar; + } + // FIXME: we'll need a better message which takes into account // which bounds actually failed to hold. self.dcx().struct_span_err( @@ -921,23 +954,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false }; let ControlFlow::Break(expr) = - (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir().body(body_id)) + (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id)) else { return false; }; let Some(typeck) = &self.typeck_results else { return false; }; - let Some((ObligationCauseCode::QuestionMark, Some(y))) = - obligation.cause.code().parent_with_predicate() - else { + let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else { return false; }; - if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) { - return false; - } let self_ty = trait_pred.skip_binder().self_ty(); let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type()); + self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred); let mut prev_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), @@ -1008,7 +1037,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let [arg] = args && let hir::ExprKind::Closure(closure) = arg.kind // The closure has a block for its body with no tail expression - && let body = self.tcx.hir().body(closure.body) + && let body = self.tcx.hir_body(closure.body) && let hir::ExprKind::Block(block, _) = body.value.kind && let None = block.expr // The last statement is of a type that can be converted to the return error type @@ -1102,6 +1131,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { suggested } + fn note_missing_impl_for_question_mark( + &self, + err: &mut Diag<'_>, + self_ty: Ty<'_>, + found_ty: Option<Ty<'_>>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) { + match (self_ty.kind(), found_ty) { + (ty::Adt(def, _), Some(ty)) + if let ty::Adt(found, _) = ty.kind() + && def.did().is_local() + && found.did().is_local() => + { + err.span_note( + self.tcx.def_span(def.did()), + format!("`{self_ty}` needs to implement `From<{ty}>`"), + ); + err.span_note( + self.tcx.def_span(found.did()), + format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"), + ); + } + (ty::Adt(def, _), None) if def.did().is_local() => { + err.span_note( + self.tcx.def_span(def.did()), + format!( + "`{self_ty}` needs to implement `{}`", + trait_pred.skip_binder().trait_ref.print_only_trait_path(), + ), + ); + } + (ty::Adt(def, _), Some(ty)) if def.did().is_local() => { + err.span_note( + self.tcx.def_span(def.did()), + format!("`{self_ty}` needs to implement `From<{ty}>`"), + ); + } + (_, Some(ty)) + if let ty::Adt(def, _) = ty.kind() + && def.did().is_local() => + { + err.span_note( + self.tcx.def_span(def.did()), + format!("`{ty}` needs to implement `Into<{self_ty}>`"), + ); + } + _ => {} + } + } + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -1443,7 +1522,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let [associated_item]: &[ty::AssocItem] = &associated_items[..] else { return None; }; - match self.tcx.hir().get_if_local(associated_item.def_id) { + match self.tcx.hir_get_if_local(associated_item.def_id) { Some( hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(_, Some(ty)), @@ -1510,7 +1589,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span = match fn_decl.output { hir::FnRetTy::Return(ty) => ty.span, hir::FnRetTy::DefaultReturn(_) => { - let body = self.tcx.hir().body(id); + let body = self.tcx.hir_body(id); match body.value.kind { hir::ExprKind::Block( hir::Block { expr: Some(expr), .. }, @@ -2031,6 +2110,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return false; } if let &[cand] = &candidates[..] { + if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id) + && !self.tcx.features().enabled(sym::try_trait_v2) + { + return false; + } let (desc, mention_castable) = match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) { (ty::FnPtr(..), ty::FnDef(..)) => { @@ -2353,7 +2437,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligated_types: &mut Vec<Ty<'tcx>>, cause_code: &ObligationCauseCode<'tcx>, ) -> bool { - if let ObligationCauseCode::BuiltinDerived(ref data) = cause_code { + if let ObligationCauseCode::BuiltinDerived(data) = cause_code { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let self_ty = parent_trait_ref.skip_binder().self_ty(); if obligated_types.iter().any(|ot| ot == &self_ty) { @@ -2846,7 +2930,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => None, }; - let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did)); + let found_node = found_did.and_then(|did| self.tcx.hir_get_if_local(did)); let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did)); if !self.reported_signature_mismatch.borrow_mut().insert((span, found_span)) { @@ -2892,7 +2976,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if found.len() != expected.len() { let (closure_span, closure_arg_span, found) = found_did .and_then(|did| { - let node = self.tcx.hir().get_if_local(did)?; + let node = self.tcx.hir_get_if_local(did)?; let (found_span, closure_arg_span, found) = self.get_fn_like_arguments(node)?; Some((Some(found_span), closure_arg_span, found)) }) @@ -2942,7 +3026,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) => ( fn_decl_span, fn_arg_span, - hir.body(body) + self.tcx + .hir_body(body) .params .iter() .map(|arg| { @@ -3204,7 +3289,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(obligation.cause.body_id) }; if let Some(def_id) = def_id - && let Some(generics) = self.tcx.hir().get_generics(def_id) + && let Some(generics) = self.tcx.hir_get_generics(def_id) { err.span_suggestion_verbose( generics.tail_span_for_predicate_suggestion(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 658fb4009d5..4d87a93be0c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -68,8 +68,8 @@ impl<'hir> FindExprBySpan<'hir> { impl<'v> Visitor<'v> for FindExprBySpan<'v> { type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; - fn nested_visit_map(&mut self) -> Self::Map { - self.tcx.hir() + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx } fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { @@ -172,8 +172,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { 1 } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, ty::PredicateKind::Coerce(_) => 2, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, _ => 0, }); @@ -418,7 +418,7 @@ pub fn report_dyn_incompatibility<'tcx>( violations: &[DynCompatibilityViolation], ) -> Diag<'tcx> { let trait_str = tcx.def_path_str(trait_def_id); - let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { + let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => Some(item.ident.span), _ => None, }); @@ -587,7 +587,7 @@ fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, e // `type Alias = Box<dyn DynIncompatibleTrait>;` to // `type Alias = Box<impl DynIncompatibleTrait>;` let Some((_id, first_non_type_parent_node)) = - tcx.hir().parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_))) + tcx.hir_parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_))) else { return; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 518323f6526..f0c6e51f2a4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{AttrArgs, AttrKind, Attribute}; +use rustc_hir::{AttrArgs, Attribute}; use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; @@ -622,7 +622,14 @@ impl<'tcx> OnUnimplementedDirective { item_def_id: DefId, ) -> Result<Option<Self>, ErrorGuaranteed> { let result = if let Some(items) = attr.meta_item_list() { - Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant) + Self::parse( + tcx, + item_def_id, + &items, + attr.span(), + true, + is_diagnostic_namespace_variant, + ) } else if let Some(value) = attr.value_str() { if !is_diagnostic_namespace_variant { Ok(Some(OnUnimplementedDirective { @@ -633,7 +640,7 @@ impl<'tcx> OnUnimplementedDirective { tcx, item_def_id, value, - attr.span, + attr.span(), is_diagnostic_namespace_variant, )?), notes: Vec::new(), @@ -659,14 +666,14 @@ impl<'tcx> OnUnimplementedDirective { Ok(None) } } else if is_diagnostic_namespace_variant { - match &attr.kind { - AttrKind::Normal(p) if !matches!(p.args, AttrArgs::Empty) => { + match attr { + Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), - attr.span, - MalformedOnUnimplementedAttrLint::new(attr.span), + attr.span(), + MalformedOnUnimplementedAttrLint::new(attr.span()), ); } } @@ -675,7 +682,7 @@ impl<'tcx> OnUnimplementedDirective { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), - attr.span, + attr.span(), MissingOptionsForOnUnimplementedAttr, ) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 527d2e54e43..c7e71a626dc 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -790,8 +790,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Get the name of the callable and the arguments to be used in the suggestion. - let hir = self.tcx.hir(); - let msg = match def_id_or_name { DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) { DefKind::Ctor(CtorOf::Struct, _) => { @@ -834,7 +832,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Applicability::HasPlaceholders, ); } else if let DefIdOrName::DefId(def_id) = def_id_or_name { - let name = match hir.get_if_local(def_id) { + let name = match self.tcx.hir_get_if_local(def_id) { Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }), .. @@ -878,7 +876,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span.remove_mark(); } let mut expr_finder = FindExprBySpan::new(span, self.tcx); - let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { + let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else { return; }; expr_finder.visit_expr(body.value); @@ -950,7 +948,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> bool { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); self.enter_forall(self_ty, |ty: Ty<'_>| { - let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { + let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else { return false; }; let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; @@ -976,7 +974,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ExprKind::MethodCall( hir::PathSegment { ident, .. }, _receiver, - &[], + [], call_span, ), hir_id, @@ -1349,8 +1347,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Issue #104961, we need to add parentheses properly for compound expressions // for example, `x.starts_with("hi".to_string() + "you")` // should be `x.starts_with(&("hi".to_string() + "you"))` - let Some(body) = - self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) + let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else { return false; }; @@ -1449,7 +1446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span.remove_mark(); } let mut expr_finder = super::FindExprBySpan::new(span, self.tcx); - let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { + let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else { return false; }; expr_finder.visit_expr(body.value); @@ -1555,7 +1552,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, ) { - let hir = self.tcx.hir(); if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id) { @@ -1565,7 +1561,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // it is from the local crate. // use nth(1) to skip one layer of desugaring from `IntoIter::into_iter` - if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1) + if let Some((_, hir::Node::Expr(await_expr))) = self.tcx.hir_parent_iter(*hir_id).nth(1) && let Some(expr_span) = expr.span.find_ancestor_inside_same_ctxt(await_expr.span) { let removal_span = self @@ -1595,7 +1591,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let ty = typeck_results.expr_ty_adjusted(base) && let ty::FnDef(def_id, _args) = ty.kind() && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = - hir.get_if_local(*def_id) + self.tcx.hir_get_if_local(*def_id) { let msg = format!("alternatively, consider making `fn {ident}` asynchronous"); if vis_span.is_empty() { @@ -1703,10 +1699,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span: Span, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { - let hir = self.tcx.hir(); let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id); if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn {sig, body: body_id, .. }, .. }) = node - && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind + && let hir::ExprKind::Block(blk, _) = &self.tcx.hir_body(*body_id).value.kind && sig.decl.output.span().overlaps(span) && blk.expr.is_none() && trait_pred.self_ty().skip_binder().is_unit() @@ -1769,7 +1764,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.children.clear(); let span = obligation.cause.span; - let body = self.tcx.hir().body_owned_by(obligation.cause.body_id); + let body = self.tcx.hir_body_owned_by(obligation.cause.body_id); let mut visitor = ReturnsVisitor::default(); visitor.visit_body(&body); @@ -2303,7 +2298,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let coroutine_body = - coroutine_did.as_local().and_then(|def_id| hir.maybe_body_owned_by(def_id)); + coroutine_did.as_local().and_then(|def_id| self.tcx.hir_maybe_body_owned_by(def_id)); let mut visitor = AwaitsVisitor::default(); if let Some(body) = coroutine_body { visitor.visit_body(&body); @@ -2685,7 +2680,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression - | ObligationCauseCode::UnifyReceiver(..) | ObligationCauseCode::Misc | ObligationCauseCode::WellFormed(..) | ObligationCauseCode::MatchImpl(..) @@ -2790,7 +2784,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { generics, kind: hir::TraitItemKind::Type(bounds, None), .. - })) = tcx.hir().get_if_local(item_def_id) + })) = tcx.hir_get_if_local(item_def_id) // Do not suggest relaxing if there is an explicit `Sized` obligation. && !bounds.iter() .filter_map(|bound| bound.trait_ref()) @@ -3293,12 +3287,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); + if tcx.is_diagnostic_item(sym::FromResidual, parent_def_id) + && !tcx.features().enabled(sym::try_trait_v2) + { + // If `#![feature(try_trait_v2)]` is not enabled, then there's no point on + // talking about `FromResidual<Result<A, B>>`, as the end user has nothing they + // can do about it. As far as they are concerned, `?` is compiler magic. + return; + } let self_ty_str = tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; - match tcx.hir().get_if_local(data.impl_or_alias_def_id) { + match tcx.hir_get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Trait(is_auto, ..), ident, @@ -3423,7 +3425,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .map_bound(|pred| pred.trait_ref) .print_only_trait_path(), ); - match tcx.hir().get_if_local(data.impl_def_id) { + match tcx.hir_get_if_local(data.impl_def_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), .. @@ -3564,7 +3566,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let expr = tcx.hir().expect_expr(hir_id); (expr_ty, expr) } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() - && let body = tcx.hir().body(body_id) + && let body = tcx.hir_body(body_id) && let hir::ExprKind::Block(block, _) = body.value.kind && let Some(expr) = block.expr && let Some(expr_ty) = self @@ -3841,7 +3843,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let hir::ExprKind::Closure(hir::Closure { body, fn_decl_span, .. }) = value.kind - && let body = tcx.hir().body(*body) + && let body = tcx.hir_body(*body) && !matches!(body.value.kind, hir::ExprKind::Block(..)) { // Check if the failed predicate was an expectation of a closure type @@ -4068,7 +4070,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let [arg] = args && let hir::ExprKind::Closure(closure) = arg.kind { - let body = tcx.hir().body(closure.body); + let body = tcx.hir_body(closure.body); if let hir::ExprKind::Block(block, None) = body.value.kind && let None = block.expr && let [.., stmt] = block.stmts @@ -4114,8 +4116,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let ty::Param(..) = ty.kind() else { continue; }; - let hir = tcx.hir(); - let node = tcx.hir_node_by_def_id(hir.get_parent_item(expr.hir_id).def_id); + let node = + tcx.hir_node_by_def_id(tcx.hir_get_parent_item(expr.hir_id).def_id); let pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref: ty::TraitRef::new( @@ -4133,7 +4135,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; suggest_restriction( tcx, - hir.body_owner_def_id(body_id), + tcx.hir_body_owner_def_id(body_id), generics, &format!("type parameter `{ty}`"), err, @@ -4355,7 +4357,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { term: ty.into(), }), )); - let body_def_id = self.tcx.hir().enclosing_body_owner(body_id); + let body_def_id = self.tcx.hir_enclosing_body_owner(body_id); // Add `<ExprTy as Iterator>::Item = _` obligation. ocx.register_obligation(Obligation::misc( self.tcx, @@ -4761,7 +4763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { let mut sugg_spans = vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())]; - let body = self.tcx.hir().body(body_id); + let body = self.tcx.hir_body(body_id); if let hir::ExprKind::Block(b, _) = body.value.kind && b.expr.is_none() { @@ -4807,7 +4809,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { debug!(?pred, ?item_def_id, ?span); let (Some(node), true) = ( - self.tcx.hir().get_if_local(item_def_id), + self.tcx.hir_get_if_local(item_def_id), self.tcx.is_lang_item(pred.def_id(), LangItem::Sized), ) else { return; @@ -5248,7 +5250,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( // If there's a body, we also need to wrap it in `async {}` if let hir::TraitFn::Provided(body) = body { - let body = tcx.hir().body(body); + let body = tcx.hir_body(body); let body_span = body.value.span; let body_span_without_braces = body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1)); diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 62cac5b17bd..23aa3800660 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -509,21 +509,18 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { let node = self.tcx.hir_node_by_def_id(anon_reg.scope); let is_impl = matches!(&node, hir::Node::ImplItem(_)); let (generics, parent_generics) = match node { - hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Fn { ref generics, .. }, - .. - }) - | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => ( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) + | hir::Node::TraitItem(hir::TraitItem { generics, .. }) + | hir::Node::ImplItem(hir::ImplItem { generics, .. }) => ( generics, match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope)) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ref generics, ..), + kind: hir::ItemKind::Trait(_, _, generics, ..), .. }) | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }), + kind: hir::ItemKind::Impl(hir::Impl { generics, .. }), .. }) => Some(generics), _ => None, @@ -1119,22 +1116,6 @@ impl Subdiagnostic for ReqIntroducedLocations { } } -pub struct MoreTargeted { - pub ident: Symbol, -} - -impl Subdiagnostic for MoreTargeted { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.code(E0772); - diag.primary_message(fluent::trait_selection_more_targeted); - diag.arg("ident", self.ident); - } -} - #[derive(Diagnostic)] #[diag(trait_selection_but_needs_to_satisfy, code = E0759)] pub struct ButNeedsToSatisfy { @@ -1151,9 +1132,6 @@ pub struct ButNeedsToSatisfy { #[note(trait_selection_introduced_by_bound)] pub bound: Option<Span>, - #[subdiagnostic] - pub req_introduces_loc: Option<ReqIntroducedLocations>, - pub has_param_name: bool, pub param_name: String, pub spans_empty: bool, @@ -1857,7 +1835,7 @@ pub fn impl_trait_overcapture_suggestion<'tcx>( new_params += name_as_bounds; } - let Some(generics) = tcx.hir().get_generics(fn_def_id) else { + let Some(generics) = tcx.hir_get_generics(fn_def_id) else { // This shouldn't happen, but don't ICE. return None; }; @@ -1880,8 +1858,7 @@ pub fn impl_trait_overcapture_suggestion<'tcx>( let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id); // FIXME: This is a bit too conservative, since it ignores parens already written in AST. let (lparen, rparen) = match tcx - .hir() - .parent_iter(opaque_hir_id) + .hir_parent_iter(opaque_hir_id) .nth(1) .expect("expected ty to have a parent always") .1 diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index b752dbf3093..4601ddf678a 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -26,7 +26,7 @@ impl<'a> DescriptionCtx<'a> { .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id) .expect_local(); let span = if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + tcx.hir_get_generics(scope).and_then(|generics| generics.get_named(br.name)) { param.span } else { @@ -48,8 +48,7 @@ impl<'a> DescriptionCtx<'a> { match fr.kind { ty::LateParamRegionKind::Named(_, name) => { let span = if let Some(param) = tcx - .hir() - .get_generics(scope) + .hir_get_generics(scope) .and_then(|generics| generics.get_named(name)) { param.span diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 1af383e9200..b235d0da83c 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,7 +20,6 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(cfg_version)] -#![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iterator_try_reduce)] diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index c238e708ab8..704ba6e501d 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -67,7 +67,7 @@ impl<'tcx> ObligationStorage<'tcx> { obligations } - fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> { + fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'tcx { mem::take(&mut self.pending).into_iter() } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 7364b4aa343..982782bc57c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::{ PredicateObligation, SelectionError, }; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; use rustc_type_ir::solve::{Goal, NoSolution}; @@ -139,6 +139,7 @@ pub(super) fn fulfillment_error_for_overflow<'tcx>( } } +#[instrument(level = "debug", skip(infcx), ret)] fn find_best_leaf_obligation<'tcx>( infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, @@ -197,6 +198,9 @@ impl<'tcx> BestObligation<'tcx> { candidates.retain(|candidate| candidate.result().is_ok()); } false => { + // We always handle rigid alias candidates separately as we may not add them for + // aliases whose trait bound doesn't hold. + candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. })); // If we have >1 candidate, one may still be due to "boring" reasons, like // an alias-relate that failed to hold when deeply evaluated. We really // don't care about reasons like this. @@ -211,23 +215,12 @@ impl<'tcx> BestObligation<'tcx> { | GoalSource::AliasBoundConstCondition | GoalSource::InstantiateHigherRanked | GoalSource::AliasWellFormed - ) && match (self.consider_ambiguities, nested_goal.result()) { - (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) - | (false, Err(_)) => true, - _ => false, - } + ) && nested_goal.result().is_err() }, ) }) }); } - - // Prefer a non-rigid candidate if there is one. - if candidates.len() > 1 { - candidates.retain(|candidate| { - !matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. }) - }); - } } } @@ -266,6 +259,90 @@ impl<'tcx> BestObligation<'tcx> { ControlFlow::Break(self.obligation.clone()) } + + /// If a normalization of an associated item or a trait goal fails without trying any + /// candidates it's likely that normalizing its self type failed. We manually detect + /// such cases here. + fn detect_error_in_self_ty_normalization( + &mut self, + goal: &inspect::InspectGoal<'_, 'tcx>, + self_ty: Ty<'tcx>, + ) -> ControlFlow<PredicateObligation<'tcx>> { + assert!(!self.consider_ambiguities); + let tcx = goal.infcx().tcx; + if let ty::Alias(..) = self_ty.kind() { + let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span); + let pred = ty::PredicateKind::AliasRelate( + self_ty.into(), + infer_term.into(), + ty::AliasRelationDirection::Equate, + ); + let obligation = + Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, pred), + goal.depth() + 1, + this, + ) + }) + } else { + ControlFlow::Continue(()) + } + } + + /// It is likely that `NormalizesTo` failed without any applicable candidates + /// because the alias is not well-formed. + /// + /// As we only enter `RigidAlias` candidates if the trait bound of the associated type + /// holds, we discard these candidates in `non_trivial_candidates` and always manually + /// check this here. + fn detect_non_well_formed_assoc_item( + &mut self, + goal: &inspect::InspectGoal<'_, 'tcx>, + alias: ty::AliasTerm<'tcx>, + ) -> ControlFlow<PredicateObligation<'tcx>> { + let tcx = goal.infcx().tcx; + let obligation = Obligation::new( + tcx, + self.obligation.cause.clone(), + goal.goal().param_env, + alias.trait_ref(tcx), + ); + self.with_derived_obligation(obligation, |this| { + goal.infcx().visit_proof_tree_at_depth( + goal.goal().with(tcx, alias.trait_ref(tcx)), + goal.depth() + 1, + this, + ) + }) + } + + /// If we have no candidates, then it's likely that there is a + /// non-well-formed alias in the goal. + fn detect_error_from_empty_candidates( + &mut self, + goal: &inspect::InspectGoal<'_, 'tcx>, + ) -> ControlFlow<PredicateObligation<'tcx>> { + let tcx = goal.infcx().tcx; + let pred_kind = goal.goal().predicate.kind(); + + match pred_kind.no_bound_vars() { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => { + self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?; + } + Some(ty::PredicateKind::NormalizesTo(pred)) + if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst = + pred.alias.kind(tcx) => + { + self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?; + self.detect_non_well_formed_assoc_item(goal, pred.alias)?; + } + Some(_) | None => {} + } + + ControlFlow::Break(self.obligation.clone()) + } } impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { @@ -277,11 +354,19 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))] fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { - let candidates = self.non_trivial_candidates(goal); - trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>()); + let tcx = goal.infcx().tcx; + // Skip goals that aren't the *reason* for our goal's failure. + match (self.consider_ambiguities, goal.result()) { + (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + _ => return ControlFlow::Continue(()), + } + let pred_kind = goal.goal().predicate.kind(); - let [candidate] = candidates.as_slice() else { - return ControlFlow::Break(self.obligation.clone()); + let candidates = self.non_trivial_candidates(goal); + let candidate = match candidates.as_slice() { + [candidate] => candidate, + [] => return self.detect_error_from_empty_candidates(goal), + _ => return ControlFlow::Break(self.obligation.clone()), }; // Don't walk into impls that have `do_not_recommend`. @@ -291,13 +376,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } = candidate.kind() && goal.infcx().tcx.do_not_recommend_impl(impl_def_id) { + trace!("#[do_not_recommend] -> exit"); return ControlFlow::Break(self.obligation.clone()); } - let tcx = goal.infcx().tcx; // FIXME: Also, what about considering >1 layer up the stack? May be necessary // for normalizes-to. - let pred_kind = goal.goal().predicate.kind(); let child_mode = match pred_kind.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { ChildMode::Trait(pred_kind.rebind(pred)) @@ -390,12 +474,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } } - // Skip nested goals that aren't the *reason* for our goal's failure. - match (self.consider_ambiguities, nested_goal.result()) { - (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} - _ => continue, - } - self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 9f4ee54bd4c..4b1bc316d5f 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -11,12 +11,11 @@ use std::assert_matches::assert_matches; -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; +use rustc_middle::ty::visit::{VisitorResult, try_visit}; use rustc_middle::ty::{TyCtxt, TypeFoldable}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::EagerResolver; @@ -300,7 +299,6 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly | inspect::ProbeKind::Root { .. } - | inspect::ProbeKind::TryNormalizeNonRigid { .. } | inspect::ProbeKind::TraitCandidate { .. } | inspect::ProbeKind::OpaqueTypeStorageLookup { .. } | inspect::ProbeKind::RigidAlias { .. } => { @@ -325,7 +323,6 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { // We add a candidate even for the root evaluation if there // is only one way to prove a given goal, e.g. for `WellFormed`. inspect::ProbeKind::Root { result } - | inspect::ProbeKind::TryNormalizeNonRigid { result } | inspect::ProbeKind::TraitCandidate { source: _, result } | inspect::ProbeKind::OpaqueTypeStorageLookup { result } | inspect::ProbeKind::RigidAlias { result } => { diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs index b0b6274907d..4437fc5b029 100644 --- a/compiler/rustc_trait_selection/src/solve/select.rs +++ b/compiler/rustc_trait_selection/src/solve/select.rs @@ -175,8 +175,7 @@ fn to_selection<'tcx>( span_bug!(span, "didn't expect to select an unknowable candidate") } }, - ProbeKind::TryNormalizeNonRigid { result: _ } - | ProbeKind::NormalizedSelfTyAssembly + ProbeKind::NormalizedSelfTyAssembly | ProbeKind::UnsizeAssembly | ProbeKind::UpcastProjectionCompatibility | ProbeKind::OpaqueTypeStorageLookup { result: _ } diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 617bc87a9d2..d4502be6ccf 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -128,8 +128,7 @@ fn sized_trait_bound_spans<'tcx>( } fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { - tcx.hir() - .get_if_local(trait_def_id) + tcx.hir_get_if_local(trait_def_id) .and_then(|node| match node { hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., generics, bounds, _), @@ -187,7 +186,10 @@ fn predicates_reference_self( fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { tcx.associated_items(trait_def_id) .in_definition_order() + // We're only looking at associated type bounds .filter(|item| item.kind == ty::AssocKind::Type) + // Ignore GATs with `Self: Sized` + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied()) .filter_map(|(clause, sp)| { // Item bounds *can* have self projections, since they never get @@ -301,7 +303,7 @@ pub fn dyn_compatibility_violations_for_assoc_item( ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) .into_iter() .map(|v| { - let node = tcx.hir().get_if_local(item.def_id); + let node = tcx.hir_get_if_local(item.def_id); // Get an accurate span depending on the violation. let span = match (&v, node) { (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, @@ -346,7 +348,7 @@ fn virtual_call_violations_for_method<'tcx>( generics, kind: hir::TraitItemKind::Fn(sig, _), .. - })) = tcx.hir().get_if_local(method.def_id).as_ref() + })) = tcx.hir_get_if_local(method.def_id).as_ref() { let sm = tcx.sess.source_map(); Some(( @@ -380,7 +382,7 @@ fn virtual_call_violations_for_method<'tcx>( let span = if let Some(hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(sig, _), .. - })) = tcx.hir().get_if_local(method.def_id).as_ref() + })) = tcx.hir_get_if_local(method.def_id).as_ref() { Some(sig.decl.inputs[i].span) } else { @@ -418,7 +420,7 @@ fn virtual_call_violations_for_method<'tcx>( let span = if let Some(hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(sig, _), .. - })) = tcx.hir().get_if_local(method.def_id).as_ref() + })) = tcx.hir_get_if_local(method.def_id).as_ref() { Some(sig.decl.inputs[0].span) } else { @@ -536,10 +538,10 @@ fn receiver_for_self_ty<'tcx>( /// a pointer. /// /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in -/// a new check that `Trait` is dyn-compatible, creating a cycle (until dyn_compatible_for_dispatch -/// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>). -/// Instead, we fudge a little by introducing a new type parameter `U` such that +/// a new check that `Trait` is dyn-compatible, creating a cycle. +/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. +/// /// Written as a chalk-style query: /// ```ignore (not-rust) /// forall (U: Trait + ?Sized) { @@ -570,8 +572,6 @@ fn receiver_is_dispatchable<'tcx>( // the type `U` in the query // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now. - // FIXME(mikeyhew) this is a total hack. Once dyn_compatible_for_dispatch is stabilized, we can - // replace this with `dyn Trait` let unsized_self_ty: Ty<'tcx> = Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome); @@ -696,11 +696,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> { ControlFlow::Continue(()) } } - ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => { + ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => { // We'll deny these later in their own pass ControlFlow::Continue(()) } - ty::Alias(ty::Projection, ref data) => { + ty::Alias(ty::Projection, data) => { match self.allow_self_projections { AllowSelfProjections::Yes => { // This is a projected type `<Foo as SomeTrait>::X`. diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index f2d2dd2f3ce..e39f8e673db 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,6 +1,5 @@ use std::marker::PhantomData; -use rustc_data_structures::captures::Captures; use rustc_data_structures::obligation_forest::{ Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult, }; @@ -900,10 +899,10 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } /// Returns the set of inference variables contained in `args`. -fn args_infer_vars<'a, 'tcx>( - selcx: &SelectionContext<'a, 'tcx>, +fn args_infer_vars<'tcx>( + selcx: &SelectionContext<'_, 'tcx>, args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, -) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> { +) -> impl Iterator<Item = TyOrConstInferVar> { selcx .infcx .resolve_vars_if_possible(args) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 79e178150de..a4b6f330b9d 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -208,7 +208,7 @@ pub fn all_fields_implement_trait<'tcx>( } let field_span = tcx.def_span(field.did); - let field_ty_span = match tcx.hir().get_if_local(field.did) { + let field_ty_span = match tcx.hir_get_if_local(field.did) { Some(hir::Node::Field(field_def)) => field_def.ty.span, _ => field_span, }; diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 92098e20448..f04a5feba30 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -2,12 +2,13 @@ use rustc_data_structures::fx::FxHashSet; use rustc_infer::traits::query::type_op::DropckOutlives; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; use tracing::{debug, instrument}; +use crate::solve::NextSolverError; use crate::traits::query::NoSolution; use crate::traits::query::normalize::QueryNormalizeExt; -use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; +use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -93,6 +94,20 @@ pub fn compute_dropck_outlives_inner<'tcx>( goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, span: Span, ) -> Result<DropckOutlivesResult<'tcx>, NoSolution> { + match compute_dropck_outlives_with_errors(ocx, goal, span) { + Ok(r) => Ok(r), + Err(_) => Err(NoSolution), + } +} + +pub fn compute_dropck_outlives_with_errors<'tcx, E>( + ocx: &ObligationCtxt<'_, 'tcx, E>, + goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, + span: Span, +) -> Result<DropckOutlivesResult<'tcx>, Vec<E>> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ let tcx = ocx.infcx.tcx; let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal; @@ -149,11 +164,11 @@ pub fn compute_dropck_outlives_inner<'tcx>( dtorck_constraint_for_ty_inner( tcx, ocx.infcx.typing_env(param_env), - DUMMY_SP, + span, depth, ty, &mut constraints, - )?; + ); // "outlives" represent types/regions that may be touched // by a destructor. @@ -173,11 +188,20 @@ pub fn compute_dropck_outlives_inner<'tcx>( // do not themselves define a destructor", more or less. We have // to push them onto the stack to be expanded. for ty in constraints.dtorck_types.drain(..) { - let Normalized { value: ty, obligations } = - ocx.infcx.at(&cause, param_env).query_normalize(ty)?; - ocx.register_obligations(obligations); + let ty = if let Ok(Normalized { value: ty, obligations }) = + ocx.infcx.at(&cause, param_env).query_normalize(ty) + { + ocx.register_obligations(obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + ty + } else { + ocx.deeply_normalize(&cause, param_env, ty)?; - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + let errors = ocx.select_where_possible(); + debug!("normalize errors: {ty} ~> {errors:#?}"); + return Err(errors); + }; match ty.kind() { // All parameters live for the duration of the @@ -213,14 +237,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( depth: usize, ty: Ty<'tcx>, constraints: &mut DropckConstraint<'tcx>, -) -> Result<(), NoSolution> { +) { if !tcx.recursion_limit().value_within_limit(depth) { constraints.overflows.push(ty); - return Ok(()); + return; } if trivial_dropck_outlives(tcx, ty) { - return Ok(()); + return; } match ty.kind() { @@ -244,22 +268,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints) - })?; + }); } ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in tys.iter() { - dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - Ok::<_, NoSolution>(()) - })?, + }), ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in args.as_closure().upvar_tys() { - dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - Ok::<_, NoSolution>(()) - })?, + }), ty::CoroutineClosure(_, args) => { rustc_data_structures::stack::ensure_sufficient_stack(|| { @@ -271,10 +293,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( depth + 1, ty, constraints, - )?; + ); } - Ok::<_, NoSolution>(()) - })? + }) } ty::Coroutine(_, args) => { @@ -313,7 +334,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Adt(def, args) => { let DropckConstraint { dtorck_types, outlives, overflows } = - tcx.at(span).adt_dtorck_constraint(def.did())?; + tcx.at(span).adt_dtorck_constraint(def.did()); // FIXME: we can try to recursively `dtorck_constraint_on_ty` // there, but that needs some way to handle cycles. constraints @@ -346,9 +367,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { // By the time this code runs, all type variables ought to // be fully resolved. - return Err(NoSolution); + tcx.dcx().span_delayed_bug(span, format!("Unresolved type in dropck: {:?}.", ty)); } } - - Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index e8c2528aa6e..2f6bbd7f4cf 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -2,7 +2,7 @@ use std::fmt; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -pub use rustc_middle::traits::query::type_op::Normalize; +pub use rustc_middle::traits::query::type_op::{DeeplyNormalize, Normalize}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -28,12 +28,53 @@ where } fn perform_locally_with_next_solver( + _ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + _span: Span, + ) -> Result<Self::QueryResponse, NoSolution> { + Ok(key.value.value) + } +} + +impl<'tcx, T> super::QueryTypeOp<'tcx> for DeeplyNormalize<T> +where + T: Normalizable<'tcx> + 'tcx, +{ + type QueryResponse = T; + + fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> { + if !key.value.value.has_aliases() { Some(key.value.value) } else { None } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> { + T::type_op_method( + tcx, + CanonicalQueryInput { + typing_mode: canonicalized.typing_mode, + canonical: canonicalized.canonical.unchecked_map( + |ty::ParamEnvAnd { param_env, value }| ty::ParamEnvAnd { + param_env, + value: Normalize { value: value.value }, + }, + ), + }, + ) + } + + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, span: Span, ) -> Result<Self::QueryResponse, NoSolution> { - // FIXME(-Znext-solver): shouldn't be using old normalizer - Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value)) + ocx.deeply_normalize( + &ObligationCause::dummy_with_span(span), + key.param_env, + key.value.value, + ) + .map_err(|_| NoSolution) } } @@ -81,3 +122,14 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> { tcx.type_op_normalize_fn_sig(canonicalized) } } + +/// This impl is not needed, since we never normalize type outlives predicates +/// in the old solver, but is required by trait bounds to be happy. +impl<'tcx> Normalizable<'tcx> for ty::PolyTypeOutlivesPredicate<'tcx> { + fn type_op_method( + _tcx: TyCtxt<'tcx>, + _canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, + ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> { + unreachable!("we never normalize PolyTypeOutlivesPredicate") + } +} diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e495bdbf782..11b6b826efe 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -102,6 +102,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidate_for_tuple(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); + } else if tcx.is_lang_item(def_id, LangItem::BikeshedGuaranteedNoDrop) { + self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + obligation, + &mut candidates, + ); } else { if tcx.is_lang_item(def_id, LangItem::Clone) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -854,13 +859,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().dyn_compatible_for_dispatch() { - principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_dyn_compatible(principal.def_id()) { - principal.with_self_ty(self.tcx(), self_ty) - } else { - return; - } + principal.with_self_ty(self.tcx(), self_ty) } else { // Only auto trait bounds exist. return; @@ -920,11 +919,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // T: Trait // so it seems ok if we (conservatively) fail to accept that `Unsize` // obligation above. Should be possible to extend this in the future. - let Some(source) = obligation.self_ty().no_bound_vars() else { + let Some(trait_pred) = obligation.predicate.no_bound_vars() else { // Don't add any candidates if there are bound regions. return; }; - let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1); + let source = trait_pred.self_ty(); + let target = trait_pred.trait_ref.args.type_at(1); debug!(?source, ?target, "assemble_candidates_for_unsizing"); @@ -1183,4 +1183,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match obligation.predicate.self_ty().skip_binder().kind() { + ty::Ref(..) + | ty::Adt(..) + | ty::Tuple(_) + | ty::Array(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) + | ty::Bound(..) => { + candidates.vec.push(BikeshedGuaranteedNoDropCandidate); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + candidates.ambiguous = true; + } + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index eb4adde716a..32cbb97e314 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_type_ir::elaborate; +use thin_vec::thin_vec; use tracing::{debug, instrument}; use super::SelectionCandidate::{self, *}; @@ -130,6 +131,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitUpcastingUnsizeCandidate(idx) => { self.confirm_trait_upcasting_unsize_candidate(obligation, idx)? } + + BikeshedGuaranteedNoDropCandidate => { + self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation) + } }; // The obligations returned by confirmation are recursively evaluated @@ -1346,6 +1351,93 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("source: {source}, target: {target}"), }) } + + fn confirm_bikeshed_guaranteed_no_drop_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> ImplSource<'tcx, PredicateObligation<'tcx>> { + let mut obligations = thin_vec![]; + + let tcx = self.tcx(); + let self_ty = obligation.predicate.self_ty(); + match *self_ty.skip_binder().kind() { + // `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`. + ty::Ref(..) => {} + // `ManuallyDrop<T>` always implements `BikeshedGuaranteedNoDrop`. + ty::Adt(def, _) if def.is_manually_drop() => {} + // Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if + // their constituent types implement `BikeshedGuaranteedNoDrop`. + ty::Tuple(tys) => { + obligations.extend(tys.iter().map(|elem_ty| { + obligation.with( + tcx, + self_ty.rebind(ty::TraitRef::new( + tcx, + obligation.predicate.def_id(), + [elem_ty], + )), + ) + })); + } + ty::Array(elem_ty, _) => { + obligations.push(obligation.with( + tcx, + self_ty.rebind(ty::TraitRef::new( + tcx, + obligation.predicate.def_id(), + [elem_ty], + )), + )); + } + + // All other types implement `BikeshedGuaranteedNoDrop` only if + // they implement `Copy`. We could be smart here and short-circuit + // some trivially `Copy`/`!Copy` types, but there's no benefit. + ty::FnDef(..) + | ty::FnPtr(..) + | ty::Error(_) + | ty::Uint(_) + | ty::Int(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Pat(..) + | ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Foreign(..) + | ty::Adt(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) + | ty::Bound(..) => { + obligations.push(obligation.with( + tcx, + self_ty.map_bound(|ty| { + ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)), + [ty], + ) + }), + )); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } + + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) + } } /// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6b1e1774f03..436ce3dddd9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1949,7 +1949,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitAliasCandidate | TraitUpcastingUnsizeCandidate(_) | BuiltinObjectCandidate - | BuiltinUnsizeCandidate => false, + | BuiltinUnsizeCandidate + | BikeshedGuaranteedNoDropCandidate => false, // Non-global param candidates have already been handled, global // where-bounds get ignored. ParamCandidate(_) | ImplCandidate(_) => true, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index f39c611d19f..19d3561dd59 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -200,15 +200,12 @@ impl<'tcx> Children { } } -fn iter_children(children: &Children) -> impl Iterator<Item = DefId> + '_ { +fn iter_children(children: &Children) -> impl Iterator<Item = DefId> { let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter()); children.blanket_impls.iter().chain(nonblanket).cloned() } -fn filtered_children( - children: &mut Children, - st: SimplifiedType, -) -> impl Iterator<Item = DefId> + '_ { +fn filtered_children(children: &mut Children, st: SimplifiedType) -> impl Iterator<Item = DefId> { let nonblanket = children.non_blanket_impls.entry(st).or_default().iter(); children.blanket_impls.iter().chain(nonblanket).cloned() } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index d30363ec158..15f5cf916a4 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -47,11 +47,11 @@ pub fn expand_trait_aliases<'tcx>( queue.extend( tcx.explicit_super_predicates_of(trait_pred.def_id()) .iter_identity_copied() - .map(|(clause, span)| { + .map(|(super_clause, span)| { let mut spans = spans.clone(); spans.push(span); ( - clause.instantiate_supertrait( + super_clause.instantiate_supertrait( tcx, clause.kind().rebind(trait_pred.trait_ref), ), diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 0024316b877..165174c0bcc 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -196,7 +196,7 @@ fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[Def fn own_existential_vtable_entries_iter( tcx: TyCtxt<'_>, trait_def_id: DefId, -) -> impl Iterator<Item = DefId> + '_ { +) -> impl Iterator<Item = DefId> { let trait_methods = tcx .associated_items(trait_def_id) .in_definition_order() diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 96051ad0aa5..18906a6a8ce 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -8,8 +8,9 @@ use rustc_middle::ty::{ self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_span::Span; +use rustc_session::parse::feature_err; use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::{Span, sym}; use tracing::{debug, instrument, trace}; use crate::infer::InferCtxt; @@ -288,7 +289,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( && let Some(impl_item) = items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id) { - Some(tcx.hir().impl_item(impl_item.id).expect_type().span) + Some(tcx.hir_impl_item(impl_item.id).expect_type().span) } else { None } @@ -704,8 +705,47 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { )); } - ty::Pat(subty, _) => { + ty::Pat(subty, pat) => { self.require_sized(subty, ObligationCauseCode::Misc); + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + let mut check = |c| { + let cause = self.cause(ObligationCauseCode::Misc); + self.out.push(traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(c, subty), + )), + )); + if !tcx.features().generic_pattern_types() { + if c.has_param() { + if self.span.is_dummy() { + self.tcx().dcx().delayed_bug( + "feature error should be reported elsewhere, too", + ); + } else { + feature_err( + &self.tcx().sess, + sym::generic_pattern_types, + self.span, + "wraparound pattern type ranges cause monomorphization time errors", + ) + .emit(); + } + } + } + }; + if let Some(start) = start { + check(start) + } + if let Some(end) = end { + check(end) + } + } + } } ty::Tuple(tys) => { @@ -841,7 +881,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { ty.map_bound(|ty| { ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Copy, Some(self.span)), + self.tcx().require_lang_item( + LangItem::BikeshedGuaranteedNoDrop, + Some(self.span), + ), [ty], ) }), @@ -861,19 +904,14 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { // FIXME(#27579) RFC also considers adding trait // obligations that don't refer to Self and // checking those - - let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch(); - - if !defer_to_coercion { - if let Some(principal) = data.principal_def_id() { - self.out.push(traits::Obligation::with_depth( - tcx, - self.cause(ObligationCauseCode::WellFormed(None)), - self.recursion_depth, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)), - )); - } + if let Some(principal) = data.principal_def_id() { + self.out.push(traits::Obligation::with_depth( + tcx, + self.cause(ObligationCauseCode::WellFormed(None)), + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)), + )); } } |
