Split hir TyKind and ConstArgKind in two and update hir::Visitor
This commit is contained in:
@@ -31,7 +31,7 @@ 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;
|
||||
use crate::intravisit::{FnKind, VisitorExt};
|
||||
|
||||
#[derive(Debug, Copy, Clone, HashStable_Generic)]
|
||||
pub struct Lifetime {
|
||||
@@ -264,11 +264,55 @@ impl<'hir> PathSegment<'hir> {
|
||||
/// 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 }`).
|
||||
///
|
||||
/// The `Unambig` generic parameter represents whether the position this const is from is
|
||||
/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an
|
||||
/// ambiguous context the parameter is instantiated with an uninhabited type making the
|
||||
/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub struct ConstArg<'hir> {
|
||||
#[repr(C)]
|
||||
pub struct ConstArg<'hir, Unambig = ()> {
|
||||
#[stable_hasher(ignore)]
|
||||
pub hir_id: HirId,
|
||||
pub kind: ConstArgKind<'hir>,
|
||||
pub kind: ConstArgKind<'hir, Unambig>,
|
||||
}
|
||||
|
||||
impl<'hir> ConstArg<'hir, AmbigArg> {
|
||||
/// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position.
|
||||
///
|
||||
/// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant
|
||||
/// to be used. Care should be taken to separately handle infer consts when calling this
|
||||
/// function as it cannot be handled by downstream code making use of the returned const.
|
||||
///
|
||||
/// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
|
||||
/// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
|
||||
///
|
||||
/// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
|
||||
pub fn as_unambig_ct(&self) -> &ConstArg<'hir> {
|
||||
// SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the
|
||||
// layout is the same across different ZST type arguments.
|
||||
let ptr = self as *const ConstArg<'hir, AmbigArg> as *const ConstArg<'hir, ()>;
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> ConstArg<'hir> {
|
||||
/// Converts a `ConstArg` in an unambigous position to one in an ambiguous position. This is
|
||||
/// fallible as the [`ConstArgKind::Infer`] variant is not present in ambiguous positions.
|
||||
///
|
||||
/// Functions accepting ambiguous consts will not handle the [`ConstArgKind::Infer`] variant, if
|
||||
/// infer consts are relevant to you then care should be taken to handle them separately.
|
||||
pub fn try_as_ambig_ct(&self) -> Option<&ConstArg<'hir, AmbigArg>> {
|
||||
if let ConstArgKind::Infer(_, ()) = self.kind {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: `ConstArg` is `repr(C)` and `ConstArgKind` is marked `repr(u8)` so that the layout is
|
||||
// the same across different ZST type arguments. We also asserted that the `self` is
|
||||
// not a `ConstArgKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
|
||||
let ptr = self as *const ConstArg<'hir> as *const ConstArg<'hir, AmbigArg>;
|
||||
Some(unsafe { &*ptr })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> ConstArg<'hir> {
|
||||
@@ -283,14 +327,15 @@ impl<'hir> ConstArg<'hir> {
|
||||
match self.kind {
|
||||
ConstArgKind::Path(path) => path.span(),
|
||||
ConstArgKind::Anon(anon) => anon.span,
|
||||
ConstArgKind::Infer(span) => span,
|
||||
ConstArgKind::Infer(span, _) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`ConstArg`].
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub enum ConstArgKind<'hir> {
|
||||
#[repr(u8, C)]
|
||||
pub enum ConstArgKind<'hir, Unambig = ()> {
|
||||
/// **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 = ...`).
|
||||
@@ -298,11 +343,9 @@ pub enum ConstArgKind<'hir> {
|
||||
/// 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),
|
||||
/// This variant is not always used to represent inference consts, sometimes
|
||||
/// [`GenericArg::Infer`] is used instead.
|
||||
Infer(Span, Unambig),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
@@ -314,19 +357,24 @@ pub struct InferArg {
|
||||
|
||||
impl InferArg {
|
||||
pub fn to_ty(&self) -> Ty<'static> {
|
||||
Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id }
|
||||
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`.
|
||||
Type(&'hir Ty<'hir, AmbigArg>),
|
||||
Const(&'hir ConstArg<'hir, AmbigArg>),
|
||||
/// Inference variables in [`GenericArg`] are always represnted by
|
||||
/// `GenericArg::Infer` instead of the `Infer` variants on [`TyKind`] and
|
||||
/// [`ConstArgKind`] as it is not clear until hir ty lowering whether a
|
||||
/// `_` argument is a type or const argument.
|
||||
///
|
||||
/// However, some builtin types' generic arguments are represented by [`TyKind`]
|
||||
/// without a [`GenericArg`], instead directly storing a [`Ty`] or [`ConstArg`]. In
|
||||
/// such cases they *are* represented by the `Infer` variants on [`TyKind`] and
|
||||
/// [`ConstArgKind`] as it is not ambiguous whether the argument is a type or const.
|
||||
Infer(InferArg),
|
||||
}
|
||||
|
||||
@@ -335,7 +383,7 @@ impl GenericArg<'_> {
|
||||
match self {
|
||||
GenericArg::Lifetime(l) => l.ident.span,
|
||||
GenericArg::Type(t) => t.span,
|
||||
GenericArg::Const(c) => c.span(),
|
||||
GenericArg::Const(c) => c.as_unambig_ct().span(),
|
||||
GenericArg::Infer(i) => i.span,
|
||||
}
|
||||
}
|
||||
@@ -354,7 +402,7 @@ impl GenericArg<'_> {
|
||||
GenericArg::Lifetime(_) => "lifetime",
|
||||
GenericArg::Type(_) => "type",
|
||||
GenericArg::Const(_) => "constant",
|
||||
GenericArg::Infer(_) => "inferred",
|
||||
GenericArg::Infer(_) => "placeholder",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2915,12 +2963,63 @@ impl<'hir> AssocItemConstraintKind<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An uninhabited enum used to make `Infer` variants on [`Ty`] and [`ConstArg`] be
|
||||
/// unreachable. Zero-Variant enums are guaranteed to have the same layout as the never
|
||||
/// type.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct Ty<'hir> {
|
||||
pub enum AmbigArg {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
#[repr(C)]
|
||||
/// Represents a type in the `HIR`.
|
||||
///
|
||||
/// The `Unambig` generic parameter represents whether the position this type is from is
|
||||
/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an
|
||||
/// ambiguous context the parameter is instantiated with an uninhabited type making the
|
||||
/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
|
||||
pub struct Ty<'hir, Unambig = ()> {
|
||||
#[stable_hasher(ignore)]
|
||||
pub hir_id: HirId,
|
||||
pub kind: TyKind<'hir>,
|
||||
pub span: Span,
|
||||
pub kind: TyKind<'hir, Unambig>,
|
||||
}
|
||||
|
||||
impl<'hir> Ty<'hir, AmbigArg> {
|
||||
/// Converts a `Ty` in an ambiguous position to one in an unambiguous position.
|
||||
///
|
||||
/// Functions accepting an unambiguous types may expect the [`TyKind::Infer`] variant
|
||||
/// to be used. Care should be taken to separately handle infer types when calling this
|
||||
/// function as it cannot be handled by downstream code making use of the returned ty.
|
||||
///
|
||||
/// In practice this may mean overriding the [`Visitor::visit_infer`][visit_infer] method on hir visitors, or
|
||||
/// specifically matching on [`GenericArg::Infer`] when handling generic arguments.
|
||||
///
|
||||
/// [visit_infer]: [rustc_hir::intravisit::Visitor::visit_infer]
|
||||
pub fn as_unambig_ty(&self) -> &Ty<'hir> {
|
||||
// SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
|
||||
// the same across different ZST type arguments.
|
||||
let ptr = self as *const Ty<'hir, AmbigArg> as *const Ty<'hir, ()>;
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Ty<'hir> {
|
||||
/// Converts a `Ty` in an unambigous position to one in an ambiguous position. This is
|
||||
/// fallible as the [`TyKind::Infer`] variant is not present in ambiguous positions.
|
||||
///
|
||||
/// Functions accepting ambiguous types will not handle the [`TyKind::Infer`] variant, if
|
||||
/// infer types are relevant to you then care should be taken to handle them separately.
|
||||
pub fn try_as_ambig_ty(&self) -> Option<&Ty<'hir, AmbigArg>> {
|
||||
if let TyKind::Infer(()) = self.kind {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: `Ty` is `repr(C)` and `TyKind` is marked `repr(u8)` so that the layout is
|
||||
// the same across different ZST type arguments. We also asserted that the `self` is
|
||||
// not a `TyKind::Infer` so there is no risk of transmuting a `()` to `AmbigArg`.
|
||||
let ptr = self as *const Ty<'hir> as *const Ty<'hir, AmbigArg>;
|
||||
Some(unsafe { &*ptr })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> Ty<'hir> {
|
||||
@@ -2952,7 +3051,7 @@ impl<'hir> Ty<'hir> {
|
||||
use crate::intravisit::Visitor;
|
||||
struct MyVisitor(Vec<Span>);
|
||||
impl<'v> Visitor<'v> for MyVisitor {
|
||||
fn visit_ty(&mut self, t: &'v Ty<'v>) {
|
||||
fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) {
|
||||
if matches!(
|
||||
&t.kind,
|
||||
TyKind::Path(QPath::Resolved(_, Path {
|
||||
@@ -2968,7 +3067,7 @@ impl<'hir> Ty<'hir> {
|
||||
}
|
||||
|
||||
let mut my_visitor = MyVisitor(vec![]);
|
||||
my_visitor.visit_ty(self);
|
||||
my_visitor.visit_unambig_ty(self);
|
||||
my_visitor.0
|
||||
}
|
||||
|
||||
@@ -2977,14 +3076,14 @@ impl<'hir> Ty<'hir> {
|
||||
pub fn is_suggestable_infer_ty(&self) -> bool {
|
||||
fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool {
|
||||
generic_args.iter().any(|arg| match arg {
|
||||
GenericArg::Type(ty) => ty.is_suggestable_infer_ty(),
|
||||
GenericArg::Type(ty) => ty.as_unambig_ty().is_suggestable_infer_ty(),
|
||||
GenericArg::Infer(_) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
debug!(?self);
|
||||
match &self.kind {
|
||||
TyKind::Infer => true,
|
||||
TyKind::Infer(()) => true,
|
||||
TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
|
||||
TyKind::Array(ty, length) => {
|
||||
ty.is_suggestable_infer_ty() || matches!(length.kind, ConstArgKind::Infer(..))
|
||||
@@ -3198,7 +3297,9 @@ pub enum InferDelegationKind {
|
||||
|
||||
/// The various kinds of types recognized by the compiler.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum TyKind<'hir> {
|
||||
// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible
|
||||
#[repr(u8, C)]
|
||||
pub enum TyKind<'hir, Unambig = ()> {
|
||||
/// Actual type should be inherited from `DefId` signature
|
||||
InferDelegation(DefId, InferDelegationKind),
|
||||
/// A variable length slice (i.e., `[T]`).
|
||||
@@ -3234,18 +3335,16 @@ pub enum TyKind<'hir> {
|
||||
TraitObject(&'hir [PolyTraitRef<'hir>], TaggedRef<'hir, Lifetime, TraitObjectSyntax>),
|
||||
/// Unused for now.
|
||||
Typeof(&'hir AnonConst),
|
||||
/// `TyKind::Infer` means the type should be inferred instead of it having been
|
||||
/// specified. This can appear anywhere in a type.
|
||||
///
|
||||
/// **Note:** Not all inferred types are represented as
|
||||
/// `TyKind::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,
|
||||
/// Placeholder for a type that has failed to be defined.
|
||||
Err(rustc_span::ErrorGuaranteed),
|
||||
/// Pattern types (`pattern_type!(u32 is 1..)`)
|
||||
Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
|
||||
/// `TyKind::Infer` means the type should be inferred instead of it having been
|
||||
/// specified. This can appear anywhere in a type.
|
||||
///
|
||||
/// This variant is not always used to represent inference types, sometimes
|
||||
/// [`GenericArg::Infer`] is used instead.
|
||||
Infer(Unambig),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
|
||||
Reference in New Issue
Block a user