X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_hir%2Fsrc%2Fhir.rs;h=4adfbdcf445d7fb4d69221334f8dd6e5fae3c573;hb=7907385999b4a83d37ed31d334f3ed9ca02983a1;hp=2d01673b61d315a6412be74cbe8bfcd40bccd026;hpb=ac46e17c02c7be374827c2f9df899cd053659dff;p=rust.git diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2d01673b61d..4adfbdcf445 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -17,7 +17,7 @@ use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::{SourceMap, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -49,15 +49,15 @@ pub enum ParamName { /// Synthetic name generated when user elided a lifetime in an impl header. /// /// E.g., the lifetimes in cases like these: - /// - /// impl Foo for &u32 - /// impl Foo<'_> for u32 - /// + /// ```ignore (fragment) + /// impl Foo for &u32 + /// impl Foo<'_> for u32 + /// ``` /// in that case, we rewrite to - /// - /// impl<'f> Foo for &'f u32 - /// impl<'f> Foo<'f> for u32 - /// + /// ```ignore (fragment) + /// impl<'f> Foo for &'f u32 + /// impl<'f> Foo<'f> for u32 + /// ``` /// where `'f` is something like `Fresh(0)`. The indices are /// unique per impl, but not necessarily continuous. Fresh(LocalDefId), @@ -93,8 +93,6 @@ pub enum LifetimeName { Param(ParamName), /// User wrote nothing (e.g., the lifetime in `&u32`). - /// - /// The bool indicates whether the user should have written something. Implicit, /// Implicit lifetime in a context like `dyn Foo`. This is @@ -444,9 +442,6 @@ pub enum GenericBound<'hir> { Outlives(Lifetime), } -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(GenericBound<'_>, 48); - impl GenericBound<'_> { pub fn trait_ref(&self) -> Option<&TraitRef<'_>> { match self { @@ -501,61 +496,25 @@ pub enum GenericParamKind<'hir> { pub struct GenericParam<'hir> { pub hir_id: HirId, pub name: ParamName, - pub bounds: GenericBounds<'hir>, pub span: Span, pub pure_wrt_drop: bool, pub kind: GenericParamKind<'hir>, + pub colon_span: Option, } impl<'hir> GenericParam<'hir> { - pub fn bounds_span_for_suggestions(&self) -> Option { - self.bounds - .iter() - .fold(None, |span: Option, bound| { - // We include bounds that come from a `#[derive(_)]` but point at the user's code, - // as we use this method to get a span appropriate for suggestions. - if !bound.span().can_be_used_for_suggestions() { - None - } else { - let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span()); - Some(span) - } - }) - .map(|sp| sp.shrink_to_hi()) + /// Synthetic type-parameters are inserted after normal ones. + /// In order for normal parameters to be able to refer to synthetic ones, + /// scans them first. + pub fn is_impl_trait(&self) -> bool { + matches!(self.kind, GenericParamKind::Type { synthetic: true, .. }) } - /// Returns the span of `:` after a generic parameter. - /// - /// For example: + /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`. /// - /// ```text - /// fn a() - /// ^ - /// | here - /// here | - /// v - /// fn b() - /// - /// fn c() - /// ^ - /// | - /// here - /// ``` - pub fn colon_span_for_suggestions(&self, source_map: &SourceMap) -> Option { - let sp = source_map - .span_extend_while(self.span.shrink_to_hi(), |c| c.is_whitespace() || c == ':') - .ok()?; - - let snippet = source_map.span_to_snippet(sp).ok()?; - let offset = snippet.find(':')?; - - let colon_sp = sp - .with_lo(BytePos(sp.lo().0 + offset as u32)) - .with_hi(BytePos(sp.lo().0 + (offset + ':'.len_utf8()) as u32)); - - Some(colon_sp) + /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information. + pub fn is_elided_lifetime(&self) -> bool { + matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided }) } } @@ -572,17 +531,22 @@ pub struct GenericParamCount { #[derive(Debug, HashStable_Generic)] pub struct Generics<'hir> { pub params: &'hir [GenericParam<'hir>], - pub where_clause: WhereClause<'hir>, + pub predicates: &'hir [WherePredicate<'hir>], + pub has_where_clause: bool, + pub where_clause_span: Span, pub span: Span, } impl<'hir> Generics<'hir> { - pub const fn empty() -> Generics<'hir> { - Generics { + pub const fn empty() -> &'hir Generics<'hir> { + const NOPE: Generics<'_> = Generics { params: &[], - where_clause: WhereClause { predicates: &[], span: DUMMY_SP }, + predicates: &[], + has_where_clause: false, + where_clause_span: DUMMY_SP, span: DUMMY_SP, - } + }; + &NOPE } pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> { @@ -601,32 +565,122 @@ pub fn spans(&self) -> MultiSpan { self.params.iter().map(|p| p.span).collect::>().into() } } -} -/// A where-clause in a definition. -#[derive(Debug, HashStable_Generic)] -pub struct WhereClause<'hir> { - pub predicates: &'hir [WherePredicate<'hir>], - // Only valid if predicates aren't empty. - pub span: Span, -} + /// If there are generic parameters, return where to introduce a new one. + pub fn span_for_param_suggestion(&self) -> Option { + if self.params.iter().any(|p| self.span.contains(p.span)) { + // `fn foo(t: impl Trait)` + // ^ suggest `, T: Trait` here + let span = self.span.with_lo(self.span.hi() - BytePos(1)).shrink_to_lo(); + Some(span) + } else { + None + } + } -impl WhereClause<'_> { - pub fn span(&self) -> Option { - if self.predicates.is_empty() { None } else { Some(self.span) } + pub fn where_clause_span(&self) -> Option { + if self.predicates.is_empty() { None } else { Some(self.where_clause_span) } } - /// The `WhereClause` under normal circumstances points at either the predicates or the empty + /// The `where_span` under normal circumstances points at either the predicates or the empty /// space where the `where` clause should be. Only of use for diagnostic suggestions. pub fn span_for_predicates_or_empty_place(&self) -> Span { - self.span + self.where_clause_span } /// `Span` where further predicates would be suggested, accounting for trailing commas, like /// in `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. - pub fn tail_span_for_suggestion(&self) -> Span { + pub fn tail_span_for_predicate_suggestion(&self) -> Span { let end = self.span_for_predicates_or_empty_place().shrink_to_hi(); - self.predicates.last().map_or(end, |p| p.span()).shrink_to_hi().to(end) + if self.has_where_clause { + self.predicates + .iter() + .filter(|p| p.in_where_clause()) + .last() + .map_or(end, |p| p.span()) + .shrink_to_hi() + .to(end) + } else { + end + } + } + + pub fn bounds_for_param( + &self, + param_def_id: LocalDefId, + ) -> impl Iterator> { + self.predicates.iter().filter_map(move |pred| match pred { + WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => { + Some(bp) + } + _ => None, + }) + } + + pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option { + self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map( + |bound| { + // We include bounds that come from a `#[derive(_)]` but point at the user's code, + // as we use this method to get a span appropriate for suggestions. + let bs = bound.span(); + if bs.can_be_used_for_suggestions() { Some(bs.shrink_to_hi()) } else { None } + }, + ) + } + + pub fn span_for_predicate_removal(&self, pos: usize) -> Span { + let predicate = &self.predicates[pos]; + let span = predicate.span(); + + if !predicate.in_where_clause() { + // + // ^^^^^^^^ + return span; + } + + // We need to find out which comma to remove. + if pos < self.predicates.len() - 1 { + let next_pred = &self.predicates[pos + 1]; + if next_pred.in_where_clause() { + // where T: ?Sized, Foo: Bar, + // ^^^^^^^^^^^ + return span.until(next_pred.span()); + } + } + + if pos > 0 { + let prev_pred = &self.predicates[pos - 1]; + if prev_pred.in_where_clause() { + // where Foo: Bar, T: ?Sized, + // ^^^^^^^^^^^ + return prev_pred.span().shrink_to_hi().to(span); + } + } + + // This is the only predicate in the where clause. + // where T: ?Sized + // ^^^^^^^^^^^^^^^ + self.where_clause_span + } + + pub fn span_for_bound_removal(&self, predicate_pos: usize, bound_pos: usize) -> Span { + let predicate = &self.predicates[predicate_pos]; + let bounds = predicate.bounds(); + + if bounds.len() == 1 { + return self.span_for_predicate_removal(predicate_pos); + } + + let span = bounds[bound_pos].span(); + if bound_pos == 0 { + // where T: ?Sized + Bar, Foo: Bar, + // ^^^^^^^^^ + span.to(bounds[1].span().shrink_to_lo()) + } else { + // where T: Bar + ?Sized, Foo: Bar, + // ^^^^^^^^^ + bounds[bound_pos - 1].span().shrink_to_hi().to(span) + } } } @@ -649,12 +703,29 @@ pub fn span(&self) -> Span { WherePredicate::EqPredicate(p) => p.span, } } + + pub fn in_where_clause(&self) -> bool { + match self { + WherePredicate::BoundPredicate(p) => p.in_where_clause, + WherePredicate::RegionPredicate(p) => p.in_where_clause, + WherePredicate::EqPredicate(_) => false, + } + } + + pub fn bounds(&self) -> GenericBounds<'hir> { + match self { + WherePredicate::BoundPredicate(p) => p.bounds, + WherePredicate::RegionPredicate(p) => p.bounds, + WherePredicate::EqPredicate(_) => &[], + } + } } /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). #[derive(Debug, HashStable_Generic)] pub struct WhereBoundPredicate<'hir> { pub span: Span, + pub in_where_clause: bool, /// Any generics from a `for` binding. pub bound_generic_params: &'hir [GenericParam<'hir>], /// The type being bounded. @@ -666,14 +737,7 @@ pub struct WhereBoundPredicate<'hir> { impl<'hir> WhereBoundPredicate<'hir> { /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. pub fn is_param_bound(&self, param_def_id: DefId) -> bool { - let TyKind::Path(QPath::Resolved(None, path)) = self.bounded_ty.kind else { - return false; - }; - match path.res { - Res::Def(DefKind::TyParam, def_id) - | Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id, - _ => false, - } + self.bounded_ty.as_generic_param().map_or(false, |(def_id, _)| def_id == param_def_id) } } @@ -681,6 +745,7 @@ pub fn is_param_bound(&self, param_def_id: DefId) -> bool { #[derive(Debug, HashStable_Generic)] pub struct WhereRegionPredicate<'hir> { pub span: Span, + pub in_where_clause: bool, pub lifetime: Lifetime, pub bounds: GenericBounds<'hir>, } @@ -1017,7 +1082,7 @@ pub enum PatKind<'hir> { /// If `slice` exists, then `after` can be non-empty. /// /// The representation for e.g., `[a, b, .., c, d]` is: - /// ``` + /// ```ignore (illustrative) /// PatKind::Slice([Binding(a), Binding(b)], Some(Wild), [Binding(c), Binding(d)]) /// ``` Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]), @@ -2080,7 +2145,7 @@ pub fn hir_id(&self) -> HirId { pub struct TraitItem<'hir> { pub ident: Ident, pub def_id: LocalDefId, - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, pub kind: TraitItemKind<'hir>, pub span: Span, } @@ -2140,7 +2205,7 @@ pub fn hir_id(&self) -> HirId { pub struct ImplItem<'hir> { pub ident: Ident, pub def_id: LocalDefId, - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, pub kind: ImplItemKind<'hir>, pub span: Span, pub vis_span: Span, @@ -2182,7 +2247,7 @@ pub enum ImplItemKind<'hir> { /// wouldn't it be better to make the `ty` field an enum like the /// following? /// -/// ``` +/// ```ignore (pseudo-rust) /// enum TypeBindingKind { /// Equals(...), /// Binding(...), @@ -2246,6 +2311,23 @@ pub struct Ty<'hir> { pub span: Span, } +impl<'hir> Ty<'hir> { + /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. + pub fn as_generic_param(&self) -> Option<(DefId, Ident)> { + let TyKind::Path(QPath::Resolved(None, path)) = self.kind else { + return None; + }; + let [segment] = &path.segments else { + return None; + }; + match path.res { + Res::Def(DefKind::TyParam, def_id) + | Res::SelfTy { trait_: Some(def_id), alias_to: None } => Some((def_id, segment.ident)), + _ => None, + } + } +} + /// Not represented directly in the AST; referred to by name through a `ty_path`. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] @@ -2345,7 +2427,7 @@ pub struct BareFnTy<'hir> { #[derive(Debug, HashStable_Generic)] pub struct OpaqueTy<'hir> { - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, } @@ -2819,7 +2901,7 @@ pub enum ItemKind<'hir> { /// A `const` item. Const(&'hir Ty<'hir>, BodyId), /// A function declaration. - Fn(FnSig<'hir>, Generics<'hir>, BodyId), + Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId), /// A MBE macro definition (`macro_rules!` or `macro`). Macro(ast::MacroDef, MacroKind), /// A module. @@ -2829,22 +2911,22 @@ pub enum ItemKind<'hir> { /// Module-level inline assembly (from `global_asm!`). GlobalAsm(&'hir InlineAsm<'hir>), /// A type alias, e.g., `type Foo = Bar`. - TyAlias(&'hir Ty<'hir>, Generics<'hir>), + TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. OpaqueTy(OpaqueTy<'hir>), /// An enum definition, e.g., `enum Foo {C, D}`. - Enum(EnumDef<'hir>, Generics<'hir>), + Enum(EnumDef<'hir>, &'hir Generics<'hir>), /// A struct definition, e.g., `struct Foo {x: A}`. - Struct(VariantData<'hir>, Generics<'hir>), + Struct(VariantData<'hir>, &'hir Generics<'hir>), /// A union definition, e.g., `union Foo {x: A, y: B}`. - Union(VariantData<'hir>, Generics<'hir>), + Union(VariantData<'hir>, &'hir Generics<'hir>), /// A trait definition. - Trait(IsAuto, Unsafety, Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), + Trait(IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), /// A trait alias. - TraitAlias(Generics<'hir>, GenericBounds<'hir>), + TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>), /// An implementation, e.g., `impl Trait for Foo { .. }`. - Impl(Impl<'hir>), + Impl(&'hir Impl<'hir>), } #[derive(Debug, HashStable_Generic)] @@ -2856,7 +2938,7 @@ pub struct Impl<'hir> { // decoding as `Span`s cannot be decoded when a `Session` is not available. pub defaultness_span: Option, pub constness: Constness, - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, /// The trait being implemented, if any. pub of_trait: Option>, @@ -2998,7 +3080,7 @@ pub fn foreign_item_id(&self) -> ForeignItemId { #[derive(Debug, HashStable_Generic)] pub enum ForeignItemKind<'hir> { /// A foreign function. - Fn(&'hir FnDecl<'hir>, &'hir [Ident], Generics<'hir>), + Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>), /// A foreign static item (`static ext: u8`). Static(&'hir Ty<'hir>, Mutability), /// A foreign type. @@ -3330,9 +3412,12 @@ mod size_asserts { rustc_data_structures::static_assert_size!(super::Pat<'static>, 88); rustc_data_structures::static_assert_size!(super::QPath<'static>, 24); rustc_data_structures::static_assert_size!(super::Ty<'static>, 72); - - rustc_data_structures::static_assert_size!(super::Item<'static>, 160); - rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128); - rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 120); - rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 112); + rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48); + rustc_data_structures::static_assert_size!(super::Generics<'static>, 56); + rustc_data_structures::static_assert_size!(super::Impl<'static>, 80); + + rustc_data_structures::static_assert_size!(super::Item<'static>, 80); + rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 88); + rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 80); + rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 72); }