forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hir.rs
4424 lines (3958 loc) · 148 KB
/
hir.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// ignore-tidy-filelength
use std::fmt;
use rustc_abi::ExternAbi;
use rustc_ast::attr::AttributeExt;
use rustc_ast::token::CommentKind;
use rustc_ast::util::parser::{AssocOp, ExprPrecedence};
use rustc_ast::{
self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitKind,
TraitObjectSyntax, UintTy,
};
pub use rustc_ast::{
AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity,
ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, MetaItemInner, MetaItemLit, Movability,
Mutability, UnOp,
};
use rustc_attr_data_structures::AttributeKind;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_index::IndexVec;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{Ident, Symbol, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Span};
use rustc_target::asm::InlineAsmRegOrRegClass;
use smallvec::SmallVec;
use thin_vec::ThinVec;
use tracing::debug;
use crate::LangItem;
use crate::def::{CtorKind, DefKind, Res};
use crate::def_id::{DefId, LocalDefIdMap};
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
use crate::intravisit::FnKind;
#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub struct Lifetime {
pub hir_id: HirId,
/// Either "`'a`", referring to a named lifetime definition,
/// `'_` referring to an anonymous lifetime (either explicitly `'_` or `&type`),
/// or "``" (i.e., `kw::Empty`) when appearing in path.
///
/// See `Lifetime::suggestion_position` for practical use.
pub ident: Ident,
/// Semantics of this lifetime.
pub res: LifetimeName,
}
#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub enum ParamName {
/// Some user-given name like `T` or `'x`.
Plain(Ident),
/// Synthetic name generated when user elided a lifetime in an impl header.
///
/// E.g., the lifetimes in cases like these:
/// ```ignore (fragment)
/// impl Foo for &u32
/// impl Foo<'_> for u32
/// ```
/// in that case, we rewrite to
/// ```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,
/// Indicates an illegal name was given and an error has been
/// reported (so we should squelch other derived errors). Occurs
/// when, e.g., `'_` is used in the wrong place.
Error,
}
impl ParamName {
pub fn ident(&self) -> Ident {
match *self {
ParamName::Plain(ident) => ident,
ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
pub enum LifetimeName {
/// User-given names or fresh (synthetic) names.
Param(LocalDefId),
/// Implicit lifetime in a context like `dyn Foo`. This is
/// distinguished from implicit lifetimes elsewhere because the
/// lifetime that they default to must appear elsewhere within the
/// enclosing type. This means that, in an `impl Trait` context, we
/// don't have to create a parameter for them. That is, `impl
/// Trait<Item = &u32>` expands to an opaque type like `type
/// Foo<'a> = impl Trait<Item = &'a u32>`, but `impl Trait<item =
/// dyn Bar>` expands to `type Foo = impl Trait<Item = dyn Bar +
/// 'static>`. The latter uses `ImplicitObjectLifetimeDefault` so
/// that surrounding code knows not to create a lifetime
/// parameter.
ImplicitObjectLifetimeDefault,
/// Indicates an error during lowering (usually `'_` in wrong place)
/// that was already reported.
Error,
/// User wrote an anonymous lifetime, either `'_` or nothing.
/// The semantics of this lifetime should be inferred by typechecking code.
Infer,
/// User wrote `'static`.
Static,
}
impl LifetimeName {
fn is_elided(&self) -> bool {
match self {
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
// It might seem surprising that `Fresh` counts as not *elided*
// -- but this is because, as far as the code in the compiler is
// concerned -- `Fresh` variants act equivalently to "some fresh name".
// They correspond to early-bound regions on an impl, in other words.
LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
}
}
}
impl fmt::Display for Lifetime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.ident.name != kw::Empty { self.ident.name.fmt(f) } else { "'_".fmt(f) }
}
}
pub enum LifetimeSuggestionPosition {
/// The user wrote `'a` or `'_`.
Normal,
/// The user wrote `&type` or `&mut type`.
Ampersand,
/// The user wrote `Path` and omitted the `<'_>`.
ElidedPath,
/// The user wrote `Path<T>`, and omitted the `'_,`.
ElidedPathArgument,
/// The user wrote `dyn Trait` and omitted the `+ '_`.
ObjectDefault,
}
impl Lifetime {
pub fn is_elided(&self) -> bool {
self.res.is_elided()
}
pub fn is_anonymous(&self) -> bool {
self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime
}
pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) {
if self.ident.name == kw::Empty {
if self.ident.span.is_empty() {
(LifetimeSuggestionPosition::ElidedPathArgument, self.ident.span)
} else {
(LifetimeSuggestionPosition::ElidedPath, self.ident.span.shrink_to_hi())
}
} else if self.res == LifetimeName::ImplicitObjectLifetimeDefault {
(LifetimeSuggestionPosition::ObjectDefault, self.ident.span)
} else if self.ident.span.is_empty() {
(LifetimeSuggestionPosition::Ampersand, self.ident.span)
} else {
(LifetimeSuggestionPosition::Normal, self.ident.span)
}
}
pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) {
debug_assert!(new_lifetime.starts_with('\''));
let (pos, span) = self.suggestion_position();
let code = match pos {
LifetimeSuggestionPosition::Normal => format!("{new_lifetime}"),
LifetimeSuggestionPosition::Ampersand => format!("{new_lifetime} "),
LifetimeSuggestionPosition::ElidedPath => format!("<{new_lifetime}>"),
LifetimeSuggestionPosition::ElidedPathArgument => format!("{new_lifetime}, "),
LifetimeSuggestionPosition::ObjectDefault => format!("+ {new_lifetime}"),
};
(span, code)
}
}
/// A `Path` is essentially Rust's notion of a name; for instance,
/// `std::cmp::PartialEq`. It's represented as a sequence of identifiers,
/// along with a bunch of supporting information.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Path<'hir, R = Res> {
pub span: Span,
/// The resolution for the path.
pub res: R,
/// The segments in the path: the things separated by `::`.
pub segments: &'hir [PathSegment<'hir>],
}
/// Up to three resolutions for type, value and macro namespaces.
pub type UsePath<'hir> = Path<'hir, SmallVec<[Res; 3]>>;
impl Path<'_> {
pub fn is_global(&self) -> bool {
!self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
}
}
/// A segment of a path: an identifier, an optional lifetime, and a set of
/// types.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PathSegment<'hir> {
/// The identifier portion of this path segment.
pub ident: Ident,
pub hir_id: HirId,
pub res: Res,
/// Type/lifetime parameters attached to this path. They come in
/// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
/// this is more than just simple syntactic sugar; the use of
/// parens affects the region binding rules, so we preserve the
/// distinction.
pub args: Option<&'hir GenericArgs<'hir>>,
/// Whether to infer remaining type parameters, if any.
/// This only applies to expression and pattern paths, and
/// out of those only the segments with no type parameters
/// to begin with, e.g., `Vec::new` is `<Vec<..>>::new::<..>`.
pub infer_args: bool,
}
impl<'hir> PathSegment<'hir> {
/// Converts an identifier to the corresponding segment.
pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> {
PathSegment { ident, hir_id, res, infer_args: true, args: None }
}
pub fn invalid() -> Self {
Self::new(Ident::empty(), HirId::INVALID, Res::Err)
}
pub fn args(&self) -> &GenericArgs<'hir> {
if let Some(ref args) = self.args {
args
} else {
const DUMMY: &GenericArgs<'_> = &GenericArgs::none();
DUMMY
}
}
}
/// A constant that enters the type system, used for arguments to const generics (e.g. array lengths).
///
/// These are distinct from [`AnonConst`] as anon consts in the type system are not allowed
/// to use any generic parameters, therefore we must represent `N` differently. Additionally
/// future designs for supporting generic parameters in const arguments will likely not use
/// an anon const based design.
///
/// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args
/// that are [just paths](ConstArgKind::Path) (currently just bare const params)
/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct ConstArg<'hir> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
pub kind: ConstArgKind<'hir>,
}
impl<'hir> ConstArg<'hir> {
pub fn anon_const_hir_id(&self) -> Option<HirId> {
match self.kind {
ConstArgKind::Anon(ac) => Some(ac.hir_id),
_ => None,
}
}
pub fn span(&self) -> Span {
match self.kind {
ConstArgKind::Path(path) => path.span(),
ConstArgKind::Anon(anon) => anon.span,
ConstArgKind::Infer(span) => span,
}
}
}
/// See [`ConstArg`].
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum ConstArgKind<'hir> {
/// **Note:** Currently this is only used for bare const params
/// (`N` where `fn foo<const N: usize>(...)`),
/// not paths to any const (`N` where `const N: usize = ...`).
///
/// However, in the future, we'll be using it for all of those.
Path(QPath<'hir>),
Anon(&'hir AnonConst),
/// **Note:** Not all inferred consts are represented as
/// `ConstArgKind::Infer`. In cases where it is ambiguous whether
/// a generic arg is a type or a const, inference variables are
/// represented as `GenericArg::Infer` instead.
Infer(Span),
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct InferArg {
pub hir_id: HirId,
pub span: Span,
}
impl InferArg {
pub fn to_ty(&self) -> Ty<'static> {
Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id }
}
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericArg<'hir> {
Lifetime(&'hir Lifetime),
Type(&'hir Ty<'hir>),
Const(&'hir ConstArg<'hir>),
/// **Note:** Inference variables are only represented as
/// `GenericArg::Infer` in cases where it is ambiguous whether
/// a generic arg is a type or a const. Otherwise, inference variables
/// are represented as `TyKind::Infer` or `ConstArgKind::Infer`.
Infer(InferArg),
}
impl GenericArg<'_> {
pub fn span(&self) -> Span {
match self {
GenericArg::Lifetime(l) => l.ident.span,
GenericArg::Type(t) => t.span,
GenericArg::Const(c) => c.span(),
GenericArg::Infer(i) => i.span,
}
}
pub fn hir_id(&self) -> HirId {
match self {
GenericArg::Lifetime(l) => l.hir_id,
GenericArg::Type(t) => t.hir_id,
GenericArg::Const(c) => c.hir_id,
GenericArg::Infer(i) => i.hir_id,
}
}
pub fn descr(&self) -> &'static str {
match self {
GenericArg::Lifetime(_) => "lifetime",
GenericArg::Type(_) => "type",
GenericArg::Const(_) => "constant",
GenericArg::Infer(_) => "inferred",
}
}
pub fn to_ord(&self) -> ast::ParamKindOrd {
match self {
GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => {
ast::ParamKindOrd::TypeOrConst
}
}
}
pub fn is_ty_or_const(&self) -> bool {
match self {
GenericArg::Lifetime(_) => false,
GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => true,
}
}
}
/// The generic arguments and associated item constraints of a path segment.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct GenericArgs<'hir> {
/// The generic arguments for this path segment.
pub args: &'hir [GenericArg<'hir>],
/// The associated item constraints for this path segment.
pub constraints: &'hir [AssocItemConstraint<'hir>],
/// Whether the arguments were written in parenthesized form (e.g., `Fn(T) -> U`).
///
/// This is required mostly for pretty-printing and diagnostics,
/// but also for changing lifetime elision rules to be "function-like".
pub parenthesized: GenericArgsParentheses,
/// The span encompassing the arguments, constraints and the surrounding brackets (`<>` or `()`).
///
/// For example:
///
/// ```ignore (illustrative)
/// Foo<A, B, AssocTy = D> Fn(T, U, V) -> W
/// ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^
/// ```
///
/// Note that this may be:
/// - empty, if there are no generic brackets (but there may be hidden lifetimes)
/// - dummy, if this was generated during desugaring
pub span_ext: Span,
}
impl<'hir> GenericArgs<'hir> {
pub const fn none() -> Self {
Self {
args: &[],
constraints: &[],
parenthesized: GenericArgsParentheses::No,
span_ext: DUMMY_SP,
}
}
/// Obtain the list of input types and the output type if the generic arguments are parenthesized.
///
/// Returns the `Ty0, Ty1, ...` and the `RetTy` in `Trait(Ty0, Ty1, ...) -> RetTy`.
/// Panics if the parenthesized arguments have an incorrect form (this shouldn't happen).
pub fn paren_sugar_inputs_output(&self) -> Option<(&[Ty<'hir>], &Ty<'hir>)> {
if self.parenthesized != GenericArgsParentheses::ParenSugar {
return None;
}
let inputs = self
.args
.iter()
.find_map(|arg| {
let GenericArg::Type(ty) = arg else { return None };
let TyKind::Tup(tys) = &ty.kind else { return None };
Some(tys)
})
.unwrap();
Some((inputs, self.paren_sugar_output_inner()))
}
/// Obtain the output type if the generic arguments are parenthesized.
///
/// Returns the `RetTy` in `Trait(Ty0, Ty1, ...) -> RetTy`.
/// Panics if the parenthesized arguments have an incorrect form (this shouldn't happen).
pub fn paren_sugar_output(&self) -> Option<&Ty<'hir>> {
(self.parenthesized == GenericArgsParentheses::ParenSugar)
.then(|| self.paren_sugar_output_inner())
}
fn paren_sugar_output_inner(&self) -> &Ty<'hir> {
let [constraint] = self.constraints.try_into().unwrap();
debug_assert_eq!(constraint.ident.name, sym::Output);
constraint.ty().unwrap()
}
pub fn has_err(&self) -> Option<ErrorGuaranteed> {
self.args
.iter()
.find_map(|arg| {
let GenericArg::Type(ty) = arg else { return None };
let TyKind::Err(guar) = ty.kind else { return None };
Some(guar)
})
.or_else(|| {
self.constraints.iter().find_map(|constraint| {
let TyKind::Err(guar) = constraint.ty()?.kind else { return None };
Some(guar)
})
})
}
#[inline]
pub fn num_lifetime_params(&self) -> usize {
self.args.iter().filter(|arg| matches!(arg, GenericArg::Lifetime(_))).count()
}
#[inline]
pub fn has_lifetime_params(&self) -> bool {
self.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
}
#[inline]
/// This function returns the number of type and const generic params.
/// It should only be used for diagnostics.
pub fn num_generic_params(&self) -> usize {
self.args.iter().filter(|arg| !matches!(arg, GenericArg::Lifetime(_))).count()
}
/// The span encompassing the arguments and constraints[^1] inside the surrounding brackets.
///
/// Returns `None` if the span is empty (i.e., no brackets) or dummy.
///
/// [^1]: Unless of the form `-> Ty` (see [`GenericArgsParentheses`]).
pub fn span(&self) -> Option<Span> {
let span_ext = self.span_ext()?;
Some(span_ext.with_lo(span_ext.lo() + BytePos(1)).with_hi(span_ext.hi() - BytePos(1)))
}
/// Returns span encompassing arguments and their surrounding `<>` or `()`
pub fn span_ext(&self) -> Option<Span> {
Some(self.span_ext).filter(|span| !span.is_empty())
}
pub fn is_empty(&self) -> bool {
self.args.is_empty()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
pub enum GenericArgsParentheses {
No,
/// Bounds for `feature(return_type_notation)`, like `T: Trait<method(..): Send>`,
/// where the args are explicitly elided with `..`
ReturnTypeNotation,
/// parenthesized function-family traits, like `T: Fn(u32) -> i32`
ParenSugar,
}
/// The modifiers on a trait bound.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct TraitBoundModifiers {
pub constness: BoundConstness,
pub polarity: BoundPolarity,
}
impl TraitBoundModifiers {
pub const NONE: Self =
TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum GenericBound<'hir> {
Trait(PolyTraitRef<'hir>),
Outlives(&'hir Lifetime),
Use(&'hir [PreciseCapturingArg<'hir>], Span),
}
impl GenericBound<'_> {
pub fn trait_ref(&self) -> Option<&TraitRef<'_>> {
match self {
GenericBound::Trait(data) => Some(&data.trait_ref),
_ => None,
}
}
pub fn span(&self) -> Span {
match self {
GenericBound::Trait(t, ..) => t.span,
GenericBound::Outlives(l) => l.ident.span,
GenericBound::Use(_, span) => *span,
}
}
}
pub type GenericBounds<'hir> = &'hir [GenericBound<'hir>];
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic, Debug)]
pub enum MissingLifetimeKind {
/// An explicit `'_`.
Underscore,
/// An elided lifetime `&' ty`.
Ampersand,
/// An elided lifetime in brackets with written brackets.
Comma,
/// An elided lifetime with elided brackets.
Brackets,
}
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum LifetimeParamKind {
// Indicates that the lifetime definition was explicitly declared (e.g., in
// `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`).
Explicit,
// Indication that the lifetime was elided (e.g., in both cases in
// `fn foo(x: &u8) -> &'_ u8 { x }`).
Elided(MissingLifetimeKind),
// Indication that the lifetime name was somehow in error.
Error,
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericParamKind<'hir> {
/// A lifetime definition (e.g., `'a: 'b + 'c + 'd`).
Lifetime {
kind: LifetimeParamKind,
},
Type {
default: Option<&'hir Ty<'hir>>,
synthetic: bool,
},
Const {
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
default: Option<&'hir ConstArg<'hir>>,
synthetic: bool,
},
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct GenericParam<'hir> {
pub hir_id: HirId,
pub def_id: LocalDefId,
pub name: ParamName,
pub span: Span,
pub pure_wrt_drop: bool,
pub kind: GenericParamKind<'hir>,
pub colon_span: Option<Span>,
pub source: GenericParamSource,
}
impl<'hir> GenericParam<'hir> {
/// 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, .. })
}
/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
///
/// 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(_) })
}
}
/// Records where the generic parameter originated from.
///
/// This can either be from an item's generics, in which case it's typically
/// early-bound (but can be a late-bound lifetime in functions, for example),
/// or from a `for<...>` binder, in which case it's late-bound (and notably,
/// does not show up in the parent item's generics).
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericParamSource {
// Early or late-bound parameters defined on an item
Generics,
// Late-bound parameters defined via a `for<...>`
Binder,
}
#[derive(Default)]
pub struct GenericParamCount {
pub lifetimes: usize,
pub types: usize,
pub consts: usize,
pub infer: usize,
}
/// Represents lifetimes and type parameters attached to a declaration
/// of a function, enum, trait, etc.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Generics<'hir> {
pub params: &'hir [GenericParam<'hir>],
pub predicates: &'hir [WherePredicate<'hir>],
pub has_where_clause_predicates: bool,
pub where_clause_span: Span,
pub span: Span,
}
impl<'hir> Generics<'hir> {
pub const fn empty() -> &'hir Generics<'hir> {
const NOPE: Generics<'_> = Generics {
params: &[],
predicates: &[],
has_where_clause_predicates: false,
where_clause_span: DUMMY_SP,
span: DUMMY_SP,
};
&NOPE
}
pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'hir>> {
self.params.iter().find(|¶m| name == param.name.ident().name)
}
/// If there are generic parameters, return where to introduce a new one.
pub fn span_for_lifetime_suggestion(&self) -> Option<Span> {
if let Some(first) = self.params.first()
&& self.span.contains(first.span)
{
// `fn foo<A>(t: impl Trait)`
// ^ suggest `'a, ` here
Some(first.span.shrink_to_lo())
} else {
None
}
}
/// If there are generic parameters, return where to introduce a new one.
pub fn span_for_param_suggestion(&self) -> Option<Span> {
self.params.iter().any(|p| self.span.contains(p.span)).then(|| {
// `fn foo<A>(t: impl Trait)`
// ^ suggest `, T: Trait` here
self.span.with_lo(self.span.hi() - BytePos(1)).shrink_to_lo()
})
}
/// `Span` where further predicates would be suggested, accounting for trailing commas, like
/// in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
pub fn tail_span_for_predicate_suggestion(&self) -> Span {
let end = self.where_clause_span.shrink_to_hi();
if self.has_where_clause_predicates {
self.predicates
.iter()
.rfind(|&p| p.kind.in_where_clause())
.map_or(end, |p| p.span)
.shrink_to_hi()
.to(end)
} else {
end
}
}
pub fn add_where_or_trailing_comma(&self) -> &'static str {
if self.has_where_clause_predicates {
","
} else if self.where_clause_span.is_empty() {
" where"
} else {
// No where clause predicates, but we have `where` token
""
}
}
pub fn bounds_for_param(
&self,
param_def_id: LocalDefId,
) -> impl Iterator<Item = &WhereBoundPredicate<'hir>> {
self.predicates.iter().filter_map(move |pred| match pred.kind {
WherePredicateKind::BoundPredicate(bp)
if bp.is_param_bound(param_def_id.to_def_id()) =>
{
Some(bp)
}
_ => None,
})
}
pub fn outlives_for_param(
&self,
param_def_id: LocalDefId,
) -> impl Iterator<Item = &WhereRegionPredicate<'_>> {
self.predicates.iter().filter_map(move |pred| match pred.kind {
WherePredicateKind::RegionPredicate(rp) if rp.is_param_bound(param_def_id) => Some(rp),
_ => None,
})
}
/// Returns a suggestable empty span right after the "final" bound of the generic parameter.
///
/// If that bound needs to be wrapped in parentheses to avoid ambiguity with
/// subsequent bounds, it also returns an empty span for an open parenthesis
/// as the second component.
///
/// E.g., adding `+ 'static` after `Fn() -> dyn Future<Output = ()>` or
/// `Fn() -> &'static dyn Debug` requires parentheses:
/// `Fn() -> (dyn Future<Output = ()>) + 'static` and
/// `Fn() -> &'static (dyn Debug) + 'static`, respectively.
pub fn bounds_span_for_suggestions(
&self,
param_def_id: LocalDefId,
) -> Option<(Span, Option<Span>)> {
self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map(
|bound| {
let span_for_parentheses = if let Some(trait_ref) = bound.trait_ref()
&& let [.., segment] = trait_ref.path.segments
&& let Some(ret_ty) = segment.args().paren_sugar_output()
&& let ret_ty = ret_ty.peel_refs()
&& let TyKind::TraitObject(
_,
_,
TraitObjectSyntax::Dyn | TraitObjectSyntax::DynStar,
) = ret_ty.kind
&& ret_ty.span.can_be_used_for_suggestions()
{
Some(ret_ty.span)
} else {
None
};
span_for_parentheses.map_or_else(
|| {
// 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();
bs.can_be_used_for_suggestions().then(|| (bs.shrink_to_hi(), None))
},
|span| Some((span.shrink_to_hi(), Some(span.shrink_to_lo()))),
)
},
)
}
pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
let predicate = &self.predicates[pos];
let span = predicate.span;
if !predicate.kind.in_where_clause() {
// <T: ?Sized, U>
// ^^^^^^^^
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.kind.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.kind.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.kind.bounds();
if bounds.len() == 1 {
return self.span_for_predicate_removal(predicate_pos);
}
let bound_span = bounds[bound_pos].span();
if bound_pos < bounds.len() - 1 {
// If there's another bound after the current bound
// include the following '+' e.g.:
//
// `T: Foo + CurrentBound + Bar`
// ^^^^^^^^^^^^^^^
bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo())
} else {
// If the current bound is the last bound
// include the preceding '+' E.g.:
//
// `T: Foo + Bar + CurrentBound`
// ^^^^^^^^^^^^^^^
bound_span.with_lo(bounds[bound_pos - 1].span().hi())
}
}
}
/// A single predicate in a where-clause.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct WherePredicate<'hir> {
pub hir_id: HirId,
pub span: Span,
pub kind: &'hir WherePredicateKind<'hir>,
}
/// The kind of a single predicate in a where-clause.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum WherePredicateKind<'hir> {
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
BoundPredicate(WhereBoundPredicate<'hir>),
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
RegionPredicate(WhereRegionPredicate<'hir>),
/// An equality predicate (unsupported).
EqPredicate(WhereEqPredicate<'hir>),
}
impl<'hir> WherePredicateKind<'hir> {
pub fn in_where_clause(&self) -> bool {
match self {
WherePredicateKind::BoundPredicate(p) => p.origin == PredicateOrigin::WhereClause,
WherePredicateKind::RegionPredicate(p) => p.in_where_clause,
WherePredicateKind::EqPredicate(_) => false,
}
}
pub fn bounds(&self) -> GenericBounds<'hir> {
match self {
WherePredicateKind::BoundPredicate(p) => p.bounds,
WherePredicateKind::RegionPredicate(p) => p.bounds,
WherePredicateKind::EqPredicate(_) => &[],
}
}
}
#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)]
pub enum PredicateOrigin {
WhereClause,
GenericParam,
ImplTrait,
}
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct WhereBoundPredicate<'hir> {
/// Origin of the predicate.
pub origin: PredicateOrigin,
/// Any generics from a `for` binding.
pub bound_generic_params: &'hir [GenericParam<'hir>],
/// The type being bounded.
pub bounded_ty: &'hir Ty<'hir>,
/// Trait and lifetime bounds (e.g., `Clone + Send + 'static`).
pub bounds: GenericBounds<'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 {
self.bounded_ty.as_generic_param().is_some_and(|(def_id, _)| def_id == param_def_id)
}
}
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct WhereRegionPredicate<'hir> {
pub in_where_clause: bool,
pub lifetime: &'hir Lifetime,
pub bounds: GenericBounds<'hir>,
}
impl<'hir> WhereRegionPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
self.lifetime.res == LifetimeName::Param(param_def_id)
}
}
/// An equality predicate (e.g., `T = int`); currently unsupported.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct WhereEqPredicate<'hir> {
pub lhs_ty: &'hir Ty<'hir>,
pub rhs_ty: &'hir Ty<'hir>,
}
/// HIR node coupled with its parent's id in the same HIR owner.
///
/// The parent is trash when the node is a HIR owner.
#[derive(Clone, Copy, Debug)]
pub struct ParentedNode<'tcx> {
pub parent: ItemLocalId,
pub node: Node<'tcx>,
}
/// Arguments passed to an attribute macro.
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub enum AttrArgs {
/// No arguments: `#[attr]`.
Empty,
/// Delimited arguments: `#[attr()/[]/{}]`.
Delimited(DelimArgs),
/// Arguments of a key-value attribute: `#[attr = "value"]`.
Eq {
/// Span of the `=` token.
eq_span: Span,
/// The "value".
expr: MetaItemLit,
},
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct AttrPath {
pub segments: Box<[Ident]>,
pub span: Span,
}
impl AttrPath {
pub fn from_ast(path: &ast::Path) -> Self {
AttrPath {
segments: path.segments.iter().map(|i| i.ident).collect::<Vec<_>>().into_boxed_slice(),
span: path.span,
}
}
}
impl fmt::Display for AttrPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.segments.iter().map(|i| i.to_string()).collect::<Vec<_>>().join("::"))
}
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct AttrItem {
// Not lowered to hir::Path because we have no NodeId to resolve to.
pub path: AttrPath,
pub args: AttrArgs,
pub id: HashIgnoredAttrId,
/// Denotes if the attribute decorates the following construct (outer)
/// or the construct this attribute is contained within (inner).
pub style: AttrStyle,
/// Span of the entire attribute
pub span: Span,
}
/// The derived implementation of [`HashStable_Generic`] on [`Attribute`]s shouldn't hash
/// [`AttrId`]s. By wrapping them in this, we make sure we never do.
#[derive(Copy, Debug, Encodable, Decodable, Clone)]
pub struct HashIgnoredAttrId {
pub attr_id: AttrId,