use super::MirBuilder;
use crate::mir::types::*;
use shape_ast::ast::{self, Expr, Span};
#[derive(Debug, Clone, Copy)]
pub(super) enum ContainerStoreKind {
Array,
Object,
Enum,
Closure,
}
pub(super) fn emit_container_store_if_needed(
builder: &mut MirBuilder,
kind: ContainerStoreKind,
container_slot: SlotId,
operands: Vec<Operand>,
span: Span,
) {
emit_container_store_with_names(builder, kind, container_slot, operands, Vec::new(), span);
}
pub(super) fn emit_container_store_with_names(
builder: &mut MirBuilder,
kind: ContainerStoreKind,
container_slot: SlotId,
operands: Vec<Operand>,
field_names: Vec<String>,
span: Span,
) {
emit_container_store_full(
builder,
kind,
container_slot,
operands,
field_names,
None,
span,
);
}
pub(super) fn emit_container_store_full(
builder: &mut MirBuilder,
kind: ContainerStoreKind,
container_slot: SlotId,
operands: Vec<Operand>,
field_names: Vec<String>,
variant_name: Option<String>,
span: Span,
) {
if operands.is_empty() {
if !matches!(kind, ContainerStoreKind::Object) {
return;
}
}
let stmt_kind = match kind {
ContainerStoreKind::Array => StatementKind::ArrayStore {
container_slot,
operands,
},
ContainerStoreKind::Object => StatementKind::ObjectStore {
container_slot,
operands,
field_names,
schema_id: None,
},
ContainerStoreKind::Enum => StatementKind::EnumStore {
container_slot,
operands,
variant_name,
},
ContainerStoreKind::Closure => StatementKind::ClosureCapture {
closure_slot: container_slot,
operands,
function_id: None, },
};
builder.push_stmt(stmt_kind, span);
}
pub(super) fn emit_task_boundary_if_needed(
builder: &mut MirBuilder,
operands: Vec<Operand>,
span: Span,
) {
if operands.is_empty() {
return;
}
let kind = if builder.async_scope_depth > 0 {
TaskBoundaryKind::Structured
} else {
TaskBoundaryKind::Detached
};
builder.push_stmt(StatementKind::TaskBoundary(operands, kind), span);
}
pub(super) fn projected_field_place(
builder: &mut MirBuilder,
base: &Place,
property: &str,
) -> Place {
Place::Field(Box::new(base.clone()), builder.field_idx(property))
}
pub(super) fn projected_index_place(base: &Place, index: usize) -> Place {
Place::Index(
Box::new(base.clone()),
Box::new(Operand::Constant(MirConstant::Int(index as i64))),
)
}
pub(super) fn assign_none(builder: &mut MirBuilder, destination: SlotId, span: Span) {
builder.push_stmt(
StatementKind::Assign(
Place::Local(destination),
Rvalue::Use(Operand::Constant(MirConstant::None)),
),
span,
);
}
pub(super) fn assign_closure_placeholder(
builder: &mut MirBuilder,
destination: SlotId,
span: Span,
) {
builder.push_stmt(
StatementKind::Assign(
Place::Local(destination),
Rvalue::Use(Operand::Constant(MirConstant::ClosurePlaceholder)),
),
span,
);
}
pub(super) fn assign_copy_from_place(
builder: &mut MirBuilder,
destination: SlotId,
place: Place,
span: Span,
) {
builder.push_stmt(
StatementKind::Assign(Place::Local(destination), Rvalue::Use(Operand::Copy(place))),
span,
);
}
pub(super) fn assign_copy_from_slot(
builder: &mut MirBuilder,
destination: SlotId,
source: SlotId,
span: Span,
) {
assign_copy_from_place(builder, destination, Place::Local(source), span);
}
pub(super) fn start_dead_block(builder: &mut MirBuilder) {
let dead_block = builder.new_block();
builder.start_block(dead_block);
}
pub(super) fn infer_local_type_from_expr(expr: &Expr) -> LocalTypeInfo {
match expr {
Expr::Literal(literal, _) => match literal {
ast::Literal::Int(_)
| ast::Literal::UInt(_)
| ast::Literal::TypedInt(_, _)
| ast::Literal::Number(_)
| ast::Literal::Decimal(_)
| ast::Literal::Bool(_)
| ast::Literal::Char(_)
| ast::Literal::None
| ast::Literal::Unit
| ast::Literal::Timeframe(_) => LocalTypeInfo::Copy,
ast::Literal::String(_) | ast::Literal::FormattedString { .. } => {
LocalTypeInfo::NonCopy
}
},
Expr::Reference { .. } => LocalTypeInfo::NonCopy,
_ => LocalTypeInfo::Unknown,
}
}
pub(super) fn lower_binary_op(op: ast::BinaryOp) -> Option<BinOp> {
match op {
ast::BinaryOp::Add => Some(BinOp::Add),
ast::BinaryOp::Sub => Some(BinOp::Sub),
ast::BinaryOp::Mul => Some(BinOp::Mul),
ast::BinaryOp::Div => Some(BinOp::Div),
ast::BinaryOp::Mod => Some(BinOp::Mod),
ast::BinaryOp::Pow => Some(BinOp::Pow),
ast::BinaryOp::BitAnd => Some(BinOp::BitAnd),
ast::BinaryOp::BitOr => Some(BinOp::BitOr),
ast::BinaryOp::BitXor => Some(BinOp::BitXor),
ast::BinaryOp::BitShl => Some(BinOp::BitShl),
ast::BinaryOp::BitShr => Some(BinOp::BitShr),
ast::BinaryOp::Greater => Some(BinOp::Gt),
ast::BinaryOp::Less => Some(BinOp::Lt),
ast::BinaryOp::GreaterEq => Some(BinOp::Ge),
ast::BinaryOp::LessEq => Some(BinOp::Le),
ast::BinaryOp::Equal => Some(BinOp::Eq),
ast::BinaryOp::NotEqual => Some(BinOp::Ne),
ast::BinaryOp::And => Some(BinOp::And),
ast::BinaryOp::Or => Some(BinOp::Or),
ast::BinaryOp::FuzzyEqual
| ast::BinaryOp::FuzzyGreater
| ast::BinaryOp::FuzzyLess
| ast::BinaryOp::NullCoalesce
| ast::BinaryOp::ErrorContext
| ast::BinaryOp::Pipe => None,
}
}
pub(super) fn is_bare_enum_variant_ctor(name: &str) -> bool {
matches!(name, "Ok" | "Err" | "Some")
}
pub(super) fn is_bare_collection_ctor(name: &str) -> bool {
matches!(
name,
"HashMap" | "Set" | "Deque" | "PriorityQueue" | "Channel" | "Mutex" | "Atomic" | "Lazy"
)
}
pub(super) fn is_bare_collection_ctor_with_arg(name: &str) -> bool {
matches!(name, "Mutex" | "Atomic" | "Lazy")
}
pub(super) fn emit_collection_ctor_store(
builder: &mut MirBuilder,
container_slot: SlotId,
operands: Vec<Operand>,
variant_name: String,
span: Span,
) {
builder.push_stmt(
StatementKind::Assign(
Place::Local(container_slot),
Rvalue::Aggregate(operands.clone()),
),
span,
);
builder.push_stmt(
StatementKind::EnumStore {
container_slot,
operands,
variant_name: Some(variant_name),
},
span,
);
}
pub(super) fn lower_unary_op(op: ast::UnaryOp) -> Option<UnOp> {
match op {
ast::UnaryOp::Neg => Some(UnOp::Neg),
ast::UnaryOp::Not => Some(UnOp::Not),
ast::UnaryOp::BitNot => Some(UnOp::BitNot),
}
}
pub(super) fn operand_crosses_task_boundary(
outer_locals_cutoff: u16,
operand: &Operand,
) -> bool {
match operand {
Operand::Copy(place) | Operand::Move(place) | Operand::MoveExplicit(place) => {
place.root_local().0 < outer_locals_cutoff
}
Operand::Constant(_) => false,
}
}