use super::visitors::*;
use super::*;
use identifiers::*;
use std::collections::HashMap;
pub mod mappers {
use super::*;
pub struct SubstLocalIds(HashMap<LocalId, LocalId>);
impl SubstLocalIds {
pub fn one(from: LocalId, to: LocalId) -> Self {
Self::many([(from, to)])
}
pub fn many(replacements: impl IntoIterator<Item = (LocalId, LocalId)>) -> Self {
Self(replacements.into_iter().collect())
}
}
impl AstVisitorMut for SubstLocalIds {
fn visit_local_id(&mut self, local_id: &mut LocalId) {
if let Some(replacement) = self.0.get(local_id) {
*local_id = replacement.clone();
}
}
}
}
impl Expr {
pub fn tuple(components: Vec<Expr>, span: Span) -> Self {
let ty = TyKind::tuple(
components
.iter()
.map(Typed::ty)
.cloned()
.map(GenericValue::Ty)
.collect(),
)
.promote();
ExprKind::tuple(components).promote(ty, span)
}
pub fn unit(span: Span) -> Self {
ExprKind::GlobalId(global_id::TupleId::Constructor { length: 0 }.into())
.promote(TyKind::unit().promote(), span)
}
pub fn standalone_fn_app(
head: impl Into<FnAppHead>,
generic_args: Vec<GenericValue>,
args: Vec<Expr>,
output_type: Ty,
span: Span,
) -> Self {
ExprKind::standalone_fn_app(head, generic_args, args, output_type.clone(), span)
.promote(output_type, span)
}
pub fn fn_app(
head: impl Into<FnAppHead>,
generic_args: Vec<GenericValue>,
args: Vec<Expr>,
output_type: Ty,
bounds_impls: Vec<ImplExpr>,
trait_: Option<(ImplExpr, Vec<GenericValue>)>,
span: Span,
) -> Self {
ExprKind::fn_app(
head,
generic_args,
args,
output_type.clone(),
bounds_impls,
trait_,
span,
)
.promote(output_type, span)
}
pub fn unbox_once(&self) -> Option<&Expr> {
if let ExprKind::App { head, args, .. } = self.kind()
&& let [arg] = &**args
&& let ExprKind::GlobalId(head) = head.kind()
&& let crate::names::alloc::boxed::Impl::new
| crate::names::rust_primitives::hax::box_new = *head
{
Some(arg)
} else {
None
}
}
pub fn underef_once(&self) -> Option<&Expr> {
if let ExprKind::App { head, args, .. } = self.kind()
&& let [arg] = &**args
&& let ExprKind::GlobalId(head) = head.kind()
&& let crate::names::rust_primitives::hax::deref_op = *head
{
Some(arg)
} else {
None
}
}
pub fn unbox_underef(&self) -> &Expr {
let mut current = self;
while let Some(e) = current.unbox_once().or_else(|| current.underef_once()) {
current = e
}
current
}
}
impl ExprKind {
pub fn standalone_fn_app(
head: impl Into<FnAppHead>,
generic_args: Vec<GenericValue>,
args: Vec<Expr>,
output_type: Ty,
span: Span,
) -> Self {
Self::fn_app(head, generic_args, args, output_type, vec![], None, span)
}
pub fn fn_app(
head: impl Into<FnAppHead>,
generic_args: Vec<GenericValue>,
args: Vec<Expr>,
output_type: Ty,
bounds_impls: Vec<ImplExpr>,
trait_: Option<(ImplExpr, Vec<GenericValue>)>,
span: Span,
) -> Self {
let head = 'head: {
let kind = match head.into() {
FnAppHead::GlobalId(global_id) => ExprKind::GlobalId(global_id),
FnAppHead::ExprKind(expr_kind) => expr_kind,
FnAppHead::Expr(expr) => break 'head expr,
};
let head_ty = TyKind::Arrow {
inputs: args.iter().map(Typed::ty).cloned().collect(),
output: output_type.clone(),
}
.promote();
kind.promote(head_ty, span)
};
Self::App {
head,
args,
generic_args,
bounds_impls,
trait_,
}
}
pub fn tuple(components: Vec<Expr>) -> Self {
let length = components.len();
ExprKind::Construct {
constructor: global_id::TupleId::Constructor { length }.into(),
is_record: false,
is_struct: true,
fields: components
.into_iter()
.enumerate()
.map(|(field, expr)| (global_id::TupleId::Field { length, field }.into(), expr))
.collect(),
base: None,
}
}
pub fn promote(self, ty: Ty, span: Span) -> Expr {
Expr {
kind: Box::new(self),
ty,
meta: Metadata {
span,
attributes: Vec::new(),
},
}
}
}
impl Metadata {
pub fn hax_attributes(&self) -> impl Iterator<Item = &hax_lib_macros_types::AttrPayload> {
crate::attributes::hax_attributes(&self.attributes)
}
}
impl Pat {
pub fn expect_self(&self) -> Option<LocalId> {
if let PatKind::Binding { var, .. } = self.kind()
&& var.is_self()
{
Some(var.clone())
} else {
None
}
}
}
pub enum FnAppHead {
GlobalId(GlobalId),
ExprKind(ExprKind),
Expr(Expr),
}
impl From<GlobalId> for FnAppHead {
fn from(value: GlobalId) -> Self {
Self::GlobalId(value)
}
}
impl From<ExprKind> for FnAppHead {
fn from(value: ExprKind) -> Self {
Self::ExprKind(value)
}
}
impl From<Expr> for FnAppHead {
fn from(value: Expr) -> Self {
Self::Expr(value)
}
}
impl Generics {
pub fn concat(mut self, other: Self) -> Self {
self.constraints.extend(other.constraints);
self.params.extend(other.params);
use std::cmp::Ordering;
self.params.sort_by(|a, b| match (a.kind(), b.kind()) {
(GenericParamKind::Lifetime, GenericParamKind::Lifetime) => Ordering::Equal,
(GenericParamKind::Lifetime, _) => Ordering::Less,
(_, GenericParamKind::Lifetime) => Ordering::Greater,
_ => Ordering::Equal,
});
self
}
pub fn empty() -> Self {
Self {
params: Vec::new(),
constraints: Vec::new(),
}
}
}
impl Item {
pub fn self_id(&self) -> Option<LocalId> {
if let ItemKind::Fn { params, .. } = self.kind()
&& let [first, ..] = ¶ms[..]
&& let Some(self_id) = first.pat.expect_self()
{
Some(self_id.clone())
} else {
None
}
}
}
impl ItemKind {
pub fn promote(self, ident: GlobalId, span: Span) -> Item {
Item {
ident,
kind: self,
meta: Metadata {
span,
attributes: Vec::new(),
},
}
}
}
impl GenericValue {
pub fn expect_ty(&self) -> Option<&Ty> {
let Self::Ty(ty) = self else { return None };
Some(ty)
}
}
impl TyKind {
pub fn tuple(args: Vec<GenericValue>) -> Self {
let head = global_id::TupleId::Type { length: args.len() }.into();
Self::App { head, args }
}
pub fn unit() -> Self {
Self::tuple(Vec::new())
}
pub fn promote(self) -> Ty {
Ty(Box::new(self))
}
}
impl Arm {
pub fn non_guarded(pat: Pat, body: Expr, span: Span) -> Self {
Self {
pat,
body,
guard: None,
meta: Metadata {
span,
attributes: Vec::new(),
},
}
}
}
impl PatKind {
pub fn var_pat(var: LocalId) -> Self {
Self::Binding {
mutable: false,
var,
mode: BindingMode::ByValue,
sub_pat: None,
}
}
pub fn promote(self, ty: Ty, span: Span) -> Pat {
Pat {
kind: Box::new(self),
ty,
meta: Metadata {
span,
attributes: Vec::new(),
},
}
}
}
impl Variant {
pub fn is_fieldless(&self) -> bool {
self.arguments.is_empty()
}
}