use crate::ast::*;
use crate::ids::Vector;
use derive_generic_visitor::*;
use std::collections::HashSet;
use std::convert::Infallible;
use std::iter::Iterator;
use std::mem;
use std::ops::Index;
impl GenericParams {
pub fn empty() -> Self {
Self::default()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn has_predicates(&self) -> bool {
!self.trait_clauses.is_empty()
|| !self.types_outlive.is_empty()
|| !self.regions_outlive.is_empty()
|| !self.trait_type_constraints.is_empty()
}
pub fn check_consistency(&self) {
assert!(self
.trait_clauses
.iter()
.enumerate()
.all(|(i, c)| c.clause_id.index() == i));
let mut s = HashSet::new();
for r in &self.regions {
if let Some(name) = &r.name {
assert!(
!s.contains(name),
"Name \"{}\" reused for two different lifetimes",
name
);
s.insert(name);
}
}
}
pub fn len(&self) -> usize {
let GenericParams {
regions,
types,
const_generics,
trait_clauses,
regions_outlive,
types_outlive,
trait_type_constraints,
} = self;
regions.len()
+ types.len()
+ const_generics.len()
+ trait_clauses.len()
+ regions_outlive.len()
+ types_outlive.len()
+ trait_type_constraints.len()
}
pub fn identity_args(&self, target: GenericsSource) -> GenericArgs {
self.identity_args_at_depth(target, DeBruijnId::zero())
}
pub fn identity_args_at_depth(&self, target: GenericsSource, depth: DeBruijnId) -> GenericArgs {
GenericArgs {
regions: self
.regions
.map_ref_indexed(|id, _| Region::Var(DeBruijnVar::bound(depth, id))),
types: self
.types
.map_ref_indexed(|id, _| TyKind::TypeVar(DeBruijnVar::bound(depth, id)).into_ty()),
const_generics: self
.const_generics
.map_ref_indexed(|id, _| ConstGeneric::Var(DeBruijnVar::bound(depth, id))),
trait_refs: self.trait_clauses.map_ref_indexed(|id, clause| TraitRef {
kind: TraitRefKind::Clause(DeBruijnVar::bound(depth, id)),
trait_decl_ref: clause.trait_.clone(),
}),
target,
}
}
}
impl<T> Binder<T> {
pub fn new(kind: BinderKind, params: GenericParams, skip_binder: T) -> Self {
Self {
params,
skip_binder,
kind,
}
}
pub fn apply(self, args: &GenericArgs) -> T
where
T: AstVisitable,
{
let mut val = self.skip_binder;
assert!(args.matches(&self.params));
val.drive_mut(&mut SubstVisitor::new(args));
val
}
}
impl<T> RegionBinder<T> {
pub fn empty(x: T) -> Self
where
T: TyVisitable,
{
RegionBinder {
regions: Default::default(),
skip_binder: x.move_under_binder(),
}
}
}
impl GenericArgs {
pub fn len(&self) -> usize {
let GenericArgs {
regions,
types,
const_generics,
trait_refs,
target: _,
} = self;
regions.len() + types.len() + const_generics.len() + trait_refs.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn empty(target: GenericsSource) -> Self {
GenericArgs {
regions: Default::default(),
types: Default::default(),
const_generics: Default::default(),
trait_refs: Default::default(),
target,
}
}
pub fn new_for_builtin(types: Vector<TypeVarId, Ty>) -> Self {
GenericArgs {
types,
..Self::empty(GenericsSource::Builtin)
}
}
pub fn new(
regions: Vector<RegionId, Region>,
types: Vector<TypeVarId, Ty>,
const_generics: Vector<ConstGenericVarId, ConstGeneric>,
trait_refs: Vector<TraitClauseId, TraitRef>,
target: GenericsSource,
) -> Self {
Self {
regions,
types,
const_generics,
trait_refs,
target,
}
}
pub fn with_target(mut self, target: GenericsSource) -> Self {
self.target = target;
self
}
pub fn matches(&self, params: &GenericParams) -> bool {
params.regions.len() == self.regions.len()
&& params.types.len() == self.types.len()
&& params.const_generics.len() == self.const_generics.len()
&& params.trait_clauses.len() == self.trait_refs.len()
}
pub fn pop_first_type_arg(&self) -> (Ty, Self) {
let mut generics = self.clone();
let mut it = mem::take(&mut generics.types).into_iter();
let ty = it.next().unwrap();
generics.types = it.collect();
(ty, generics)
}
pub fn concat(mut self, target: GenericsSource, other: &Self) -> Self {
let Self {
regions,
types,
const_generics,
trait_refs,
target: _,
} = other;
self.regions.extend_from_slice(regions);
self.types.extend_from_slice(types);
self.const_generics.extend_from_slice(const_generics);
self.trait_refs.extend_from_slice(trait_refs);
self.target = target;
self
}
}
impl GenericsSource {
pub fn item<I: Into<AnyTransId>>(id: I) -> Self {
Self::Item(id.into())
}
}
impl IntegerTy {
pub fn is_signed(&self) -> bool {
matches!(
self,
IntegerTy::Isize
| IntegerTy::I8
| IntegerTy::I16
| IntegerTy::I32
| IntegerTy::I64
| IntegerTy::I128
)
}
pub fn is_unsigned(&self) -> bool {
!(self.is_signed())
}
pub fn size(&self) -> usize {
use std::mem::size_of;
match self {
IntegerTy::Isize => size_of::<isize>(),
IntegerTy::I8 => size_of::<i8>(),
IntegerTy::I16 => size_of::<i16>(),
IntegerTy::I32 => size_of::<i32>(),
IntegerTy::I64 => size_of::<i64>(),
IntegerTy::I128 => size_of::<i128>(),
IntegerTy::Usize => size_of::<isize>(),
IntegerTy::U8 => size_of::<u8>(),
IntegerTy::U16 => size_of::<u16>(),
IntegerTy::U32 => size_of::<u32>(),
IntegerTy::U64 => size_of::<u64>(),
IntegerTy::U128 => size_of::<u128>(),
}
}
}
impl Ty {
pub fn is_unit(&self) -> bool {
match self.kind() {
TyKind::Adt(TypeId::Tuple, args) => {
assert!(args.regions.is_empty());
assert!(args.const_generics.is_empty());
args.types.is_empty()
}
_ => false,
}
}
pub fn mk_unit() -> Ty {
TyKind::Adt(TypeId::Tuple, GenericArgs::empty(GenericsSource::Builtin)).into_ty()
}
pub fn is_scalar(&self) -> bool {
match self.kind() {
TyKind::Literal(kind) => kind.is_integer(),
_ => false,
}
}
pub fn is_unsigned_scalar(&self) -> bool {
match self.kind() {
TyKind::Literal(LiteralTy::Integer(kind)) => kind.is_unsigned(),
_ => false,
}
}
pub fn is_signed_scalar(&self) -> bool {
match self.kind() {
TyKind::Literal(LiteralTy::Integer(kind)) => kind.is_signed(),
_ => false,
}
}
pub fn is_box(&self) -> bool {
match self.kind() {
TyKind::Adt(TypeId::Builtin(BuiltinTy::Box), generics) => {
assert!(generics.regions.is_empty());
assert!(generics.types.len() == 1);
assert!(generics.const_generics.is_empty());
true
}
_ => false,
}
}
pub fn as_box(&self) -> Option<&Ty> {
match self.kind() {
TyKind::Adt(TypeId::Builtin(BuiltinTy::Box), generics) => {
assert!(generics.regions.is_empty());
assert!(generics.types.len() == 1);
assert!(generics.const_generics.is_empty());
Some(&generics.types[0])
}
_ => None,
}
}
pub fn as_array_or_slice(&self) -> Option<&Ty> {
match self.kind() {
TyKind::Adt(TypeId::Builtin(BuiltinTy::Array | BuiltinTy::Slice), generics) => {
assert!(generics.regions.is_empty());
assert!(generics.types.len() == 1);
Some(&generics.types[0])
}
_ => None,
}
}
pub fn as_tuple(&self) -> Option<&Vector<TypeVarId, Ty>> {
match self.kind() {
TyKind::Adt(TypeId::Tuple, generics) => {
assert!(generics.regions.is_empty());
assert!(generics.const_generics.is_empty());
Some(&generics.types)
}
_ => None,
}
}
pub fn as_adt(&self) -> Option<(TypeId, &GenericArgs)> {
match self.kind() {
TyKind::Adt(id, generics) => Some((*id, generics)),
_ => None,
}
}
}
impl TyKind {
pub fn into_ty(self) -> Ty {
Ty::new(self)
}
}
impl From<TyKind> for Ty {
fn from(kind: TyKind) -> Ty {
kind.into_ty()
}
}
impl std::ops::Deref for Ty {
type Target = TyKind;
fn deref(&self) -> &Self::Target {
self.kind()
}
}
unsafe impl std::ops::DerefPure for Ty {}
impl TypeId {
pub fn generics_target(&self) -> GenericsSource {
match *self {
TypeId::Adt(decl_id) => GenericsSource::item(decl_id),
TypeId::Tuple | TypeId::Builtin(..) => GenericsSource::Builtin,
}
}
}
impl FunId {
pub fn generics_target(&self) -> GenericsSource {
match *self {
FunId::Regular(fun_id) => GenericsSource::item(fun_id),
FunId::Builtin(..) => GenericsSource::Builtin,
}
}
}
impl FunIdOrTraitMethodRef {
pub fn generics_target(&self) -> GenericsSource {
match self {
FunIdOrTraitMethodRef::Fun(fun_id) => fun_id.generics_target(),
FunIdOrTraitMethodRef::Trait(trait_ref, name, _) => {
GenericsSource::Method(trait_ref.trait_decl_ref.skip_binder.trait_id, name.clone())
}
}
}
}
impl Field {
pub fn renamed_name(&self) -> Option<&str> {
self.attr_info.rename.as_deref().or(self.name.as_deref())
}
pub fn is_opaque(&self) -> bool {
self.attr_info
.attributes
.iter()
.any(|attr| attr.is_opaque())
}
}
impl Variant {
pub fn renamed_name(&self) -> &str {
self.attr_info
.rename
.as_deref()
.unwrap_or(self.name.as_ref())
}
pub fn is_opaque(&self) -> bool {
self.attr_info
.attributes
.iter()
.any(|attr| attr.is_opaque())
}
}
impl RefKind {
pub fn mutable(x: bool) -> Self {
if x {
Self::Mut
} else {
Self::Shared
}
}
}
#[derive(Visitor)]
pub(crate) struct SubstVisitor<'a> {
generics: &'a GenericArgs,
binder_depth: DeBruijnId,
}
impl<'a> SubstVisitor<'a> {
pub(crate) fn new(generics: &'a GenericArgs) -> Self {
Self {
generics,
binder_depth: DeBruijnId::zero(),
}
}
fn process_var<Id, T>(&self, var: &mut DeBruijnVar<Id>) -> Option<T>
where
Id: Copy,
GenericArgs: Index<Id, Output = T>,
T: Clone + TyVisitable,
{
use std::cmp::Ordering::*;
match var {
DeBruijnVar::Bound(dbid, varid) => match (*dbid).cmp(&self.binder_depth) {
Equal => Some(
self.generics[*varid]
.clone()
.move_under_binders(self.binder_depth),
),
Greater => {
*dbid = dbid.decr();
None
}
Less => None,
},
DeBruijnVar::Free(..) => None,
}
}
}
impl VisitAstMut for SubstVisitor<'_> {
fn enter_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
self.binder_depth = self.binder_depth.incr()
}
fn exit_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
self.binder_depth = self.binder_depth.decr()
}
fn enter_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
self.binder_depth = self.binder_depth.incr()
}
fn exit_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
self.binder_depth = self.binder_depth.decr()
}
fn exit_region(&mut self, r: &mut Region) {
match r {
Region::Var(var) => {
if let Some(new_r) = self.process_var(var) {
*r = new_r;
}
}
_ => (),
}
}
fn exit_ty(&mut self, ty: &mut Ty) {
let new_ty = ty.with_kind_mut(|kind| match kind {
TyKind::TypeVar(var) => self.process_var(var),
_ => None,
});
if let Some(new_ty) = new_ty {
*ty = new_ty
}
}
fn exit_const_generic(&mut self, cg: &mut ConstGeneric) {
match cg {
ConstGeneric::Var(var) => {
if let Some(new_cg) = self.process_var(var) {
*cg = new_cg;
}
}
_ => (),
}
}
fn exit_trait_ref(&mut self, tr: &mut TraitRef) {
match &mut tr.kind {
TraitRefKind::Clause(var) => {
if let Some(new_tr) = self.process_var(var) {
*tr = new_tr;
}
}
_ => (),
}
}
}
pub trait TyVisitable: Sized + AstVisitable {
fn substitute(&mut self, generics: &GenericArgs) {
self.drive_mut(&mut SubstVisitor::new(generics));
}
fn move_under_binder(self) -> Self {
self.move_under_binders(DeBruijnId::one())
}
fn move_under_binders(mut self, depth: DeBruijnId) -> Self {
let Continue(()) = self.visit_db_id::<Infallible>(|id| {
*id = id.plus(depth);
Continue(())
});
self
}
fn move_from_under_binders(mut self, depth: DeBruijnId) -> Option<Self> {
self.visit_db_id::<()>(|id| match id.sub(depth) {
Some(sub) => {
*id = sub;
Continue(())
}
None => Break(()),
})
.is_continue()
.then_some(self)
}
fn visit_db_id<B>(
&mut self,
f: impl FnMut(&mut DeBruijnId) -> ControlFlow<B>,
) -> ControlFlow<B> {
struct Wrap<F> {
f: F,
depth: DeBruijnId,
}
impl<B, F> Visitor for Wrap<F>
where
F: FnMut(&mut DeBruijnId) -> ControlFlow<B>,
{
type Break = B;
}
impl<B, F> VisitAstMut for Wrap<F>
where
F: FnMut(&mut DeBruijnId) -> ControlFlow<B>,
{
fn enter_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
self.depth = self.depth.incr()
}
fn exit_region_binder<T: AstVisitable>(&mut self, _: &mut RegionBinder<T>) {
self.depth = self.depth.decr()
}
fn enter_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
self.depth = self.depth.incr()
}
fn exit_binder<T: AstVisitable>(&mut self, _: &mut Binder<T>) {
self.depth = self.depth.decr()
}
fn visit_de_bruijn_id(&mut self, x: &mut DeBruijnId) -> ControlFlow<Self::Break> {
if let Some(mut shifted) = x.sub(self.depth) {
(self.f)(&mut shifted)?;
*x = shifted.plus(self.depth)
}
Continue(())
}
}
self.drive_mut(&mut Wrap {
f,
depth: DeBruijnId::zero(),
})
}
}
impl<T: AstVisitable> TyVisitable for T {}
impl PartialEq for TraitClause {
fn eq(&self, other: &Self) -> bool {
self.clause_id == other.clause_id && self.trait_ == other.trait_
}
}
impl Eq for TraitClause {}
mk_index_impls!(GenericArgs.regions[RegionId]: Region);
mk_index_impls!(GenericArgs.types[TypeVarId]: Ty);
mk_index_impls!(GenericArgs.const_generics[ConstGenericVarId]: ConstGeneric);
mk_index_impls!(GenericArgs.trait_refs[TraitClauseId]: TraitRef);
mk_index_impls!(GenericParams.regions[RegionId]: RegionVar);
mk_index_impls!(GenericParams.types[TypeVarId]: TypeVar);
mk_index_impls!(GenericParams.const_generics[ConstGenericVarId]: ConstGenericVar);
mk_index_impls!(GenericParams.trait_clauses[TraitClauseId]: TraitClause);