diff options
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
8 files changed, 67 insertions, 167 deletions
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index e27e68d3662..e8237471e1b 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -1,7 +1,7 @@ +use rustc_hir::limit::Limit; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::PredicateObligations; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_session::Limit; use rustc_span::def_id::{LOCAL_CRATE, LocalDefId}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::ObligationCtxt; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b5c0ca4727c..63d0f400aef 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -85,7 +85,9 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{ + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode, +}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; @@ -233,8 +235,7 @@ fn missing_items_err( }; // Obtain the level of indentation ending in `sugg_sp`. - let padding = - tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); + let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) = (Vec::new(), Vec::new(), Vec::new()); @@ -331,6 +332,7 @@ fn default_body_is_unstable( fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, + assoc: ty::AssocItem, ) -> (String, String) { let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default(); let mut projections = vec![]; @@ -354,34 +356,50 @@ fn bounds_from_generic_predicates<'tcx>( } let mut where_clauses = vec![]; - let mut types_str = vec![]; - for (ty, bounds) in types { - if let ty::Param(_) = ty.kind() { - let mut bounds_str = vec![]; - for bound in bounds { - let mut projections_str = vec![]; - for projection in &projections { - let p = projection.skip_binder(); - if bound == tcx.parent(p.projection_term.def_id) - && p.projection_term.self_ty() == ty - { - let name = tcx.item_name(p.projection_term.def_id); - projections_str.push(format!("{} = {}", name, p.term)); + let generics = tcx.generics_of(assoc.def_id); + let types_str = generics + .own_params + .iter() + .filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. })) + .map(|p| { + // we just checked that it's a type, so the unwrap can't fail + let ty = tcx.mk_param_from_def(p).as_type().unwrap(); + if let Some(bounds) = types.get(&ty) { + let mut bounds_str = vec![]; + for bound in bounds.iter().copied() { + let mut projections_str = vec![]; + for projection in &projections { + let p = projection.skip_binder(); + if bound == tcx.parent(p.projection_term.def_id) + && p.projection_term.self_ty() == ty + { + let name = tcx.item_name(p.projection_term.def_id); + projections_str.push(format!("{} = {}", name, p.term)); + } + } + let bound_def_path = tcx.def_path_str(bound); + if projections_str.is_empty() { + where_clauses.push(format!("{}: {}", ty, bound_def_path)); + } else { + bounds_str.push(format!( + "{}<{}>", + bound_def_path, + projections_str.join(", ") + )); } } - let bound_def_path = tcx.def_path_str(bound); - if projections_str.is_empty() { - where_clauses.push(format!("{}: {}", ty, bound_def_path)); + if bounds_str.is_empty() { + ty.to_string() } else { - bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", "))); + format!("{}: {}", ty, bounds_str.join(" + ")) } - } - if bounds_str.is_empty() { - types_str.push(ty.to_string()); } else { - types_str.push(format!("{}: {}", ty, bounds_str.join(" + "))); + ty.to_string() } - } else { + }) + .collect::<Vec<_>>(); + for (ty, bounds) in types.into_iter() { + if !matches!(ty.kind(), ty::Param(_)) { // Avoid suggesting the following: // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {} where_clauses.extend( @@ -473,10 +491,10 @@ fn fn_sig_suggestion<'tcx>( let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let safety = sig.safety.prefix_str(); - let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc); // FIXME: this is not entirely correct, as the lifetimes from borrowed params will - // not be present in the `fn` definition, not will we account for renamed + // not be present in the `fn` definition, nor will we account for renamed // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. @@ -512,6 +530,7 @@ fn suggestion_signature<'tcx>( let (generics, where_clauses) = bounds_from_generic_predicates( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), + assoc, ); format!("type {}{generics} = /* Type */{where_clauses};", assoc.name()) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e6a1f6d8d8b..22a9446fd4c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1047,7 +1047,7 @@ fn check_type_defn<'tcx>( let needs_drop_copy = || { packed && { let ty = tcx.type_of(variant.tail().did).instantiate_identity(); - let ty = tcx.erase_regions(ty); + let ty = tcx.erase_and_anonymize_regions(ty); assert!(!ty.has_infer()); ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env)) } diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index f707196c816..621431ae234 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -404,7 +404,7 @@ fn emit_orphan_check_error<'tcx>( of_trait.trait_ref.path.span }; - ty = tcx.erase_regions(ty); + ty = tcx.erase_and_anonymize_regions(ty); let is_foreign = !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index b59dc4bd132..126ffabd448 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -174,12 +174,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } }; - if let Node::TraitItem(item) = node { - let mut bounds = Vec::new(); - icx.lowerer().add_default_trait_item_bounds(item, &mut bounds); - predicates.extend(bounds); - } - let generics = tcx.generics_of(def_id); // Below we'll consider the bounds on the type parameters (including `Self`) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 6565ad7cf53..3b6367219b7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -6,6 +6,7 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, }; +use rustc_hir::limit::Limit; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{Ident, Span, Symbol}; @@ -557,7 +558,7 @@ pub(crate) struct AutoDerefReachedRecursionLimit<'a> { #[label] pub span: Span, pub ty: Ty<'a>, - pub suggested_limit: rustc_session::Limit, + pub suggested_limit: Limit, pub crate_name: Symbol, } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index d14aef8ace4..99dc8e6e522 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1,12 +1,13 @@ +use std::assert_matches::assert_matches; use std::ops::ControlFlow; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; +use rustc_hir::PolyTraitRef; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_hir::{AmbigArg, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -230,122 +231,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds - /// or associated items. - /// - /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds - /// should be added everywhere, including super bounds. However this causes a huge performance - /// costs. For optimization purposes instead of adding default supertraits, bounds - /// are added to the associated items: - /// - /// ```ignore(illustrative) - /// // Default bounds are generated in the following way: - /// trait Trait { - /// fn foo(&self) where Self: Leak {} - /// } - /// - /// // instead of this: - /// trait Trait: Leak { - /// fn foo(&self) {} - /// } - /// ``` - /// It is not always possible to do this because of backward compatibility: - /// - /// ```ignore(illustrative) - /// pub trait Trait<Rhs = Self> {} - /// pub trait Trait1 : Trait {} - /// //~^ ERROR: `Rhs` requires `DefaultAutoTrait`, but `Self` is not `DefaultAutoTrait` - /// ``` - /// - /// or: - /// - /// ```ignore(illustrative) - /// trait Trait { - /// type Type where Self: Sized; - /// } - /// trait Trait2<T> : Trait<Type = T> {} - /// //~^ ERROR: `DefaultAutoTrait` required for `Trait2`, by implicit `Self: DefaultAutoTrait` in `Trait::Type` - /// ``` - /// - /// Therefore, `experimental_default_bounds` are still being added to supertraits if - /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header. - fn requires_default_supertraits( - &self, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], - hir_generics: &'tcx hir::Generics<'tcx>, - ) -> bool { - struct TraitInfoCollector; - - impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector { - type Result = ControlFlow<()>; - - fn visit_assoc_item_constraint( - &mut self, - _constraint: &'tcx hir::AssocItemConstraint<'tcx>, - ) -> Self::Result { - ControlFlow::Break(()) - } - - fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result { - if matches!( - &t.kind, - hir::TyKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. }, - )) - ) { - return ControlFlow::Break(()); - } - hir::intravisit::walk_ty(self, t) - } - } - - let mut found = false; - for bound in hir_bounds { - found |= hir::intravisit::walk_param_bound(&mut TraitInfoCollector, bound).is_break(); - } - found |= hir::intravisit::walk_generics(&mut TraitInfoCollector, hir_generics).is_break(); - found - } - - /// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if - /// they are not added as super trait bounds to the trait itself. See - /// `requires_default_supertraits` for more information. - pub(crate) fn add_default_trait_item_bounds( - &self, - trait_item: &hir::TraitItem<'tcx>, - bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - ) { - let tcx = self.tcx(); - if !tcx.sess.opts.unstable_opts.experimental_default_bounds { - return; - } - - let parent = tcx.local_parent(trait_item.hir_id().owner.def_id); - let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else { - unreachable!(); - }; - - let (trait_generics, trait_bounds) = match parent_trait.kind { - hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), - _ => unreachable!(), - }; - - if !self.requires_default_supertraits(trait_bounds, trait_generics) { - let self_ty_where_predicates = (parent, trait_item.generics.predicates); - self.add_default_traits( - bounds, - tcx.types.self_param, - &[], - Some(self_ty_where_predicates), - trait_item.span, - ); - } - } - - /// Lazily sets `experimental_default_bounds` to true on trait super bounds. - /// See `requires_default_supertraits` for more information. + /// Adds `experimental_default_bounds` bounds to the supertrait bounds. pub(crate) fn add_default_super_traits( &self, trait_def_id: LocalDefId, @@ -354,21 +240,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_generics: &'tcx hir::Generics<'tcx>, span: Span, ) { - if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds { + assert_matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias); + + // Supertraits for auto trait are unsound according to the unstable book: + // https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits + if self.tcx().trait_is_auto(trait_def_id.to_def_id()) { return; } - assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); - if self.requires_default_supertraits(hir_bounds, hir_generics) { - let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); - self.add_default_traits( - bounds, - self.tcx().types.self_param, - hir_bounds, - Some(self_ty_where_predicates), - span, - ); - } + self.add_default_traits( + bounds, + self.tcx().types.self_param, + hir_bounds, + Some((trait_def_id, hir_generics.predicates)), + span, + ); } pub(crate) fn add_default_traits( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 93b82acf621..0cf9cb7193f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -482,7 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|header| header.trait_ref.instantiate_identity().self_ty()) // We don't care about blanket impls. .filter(|self_ty| !self_ty.has_non_region_param()) - .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .map(|self_ty| tcx.erase_and_anonymize_regions(self_ty).to_string()) .collect() }; // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that |
