use super::specialization::{
SpecializationKey, SpecializedCustomValueShape, SpecializedFunctionShape, SpecializedValueShape,
};
use super::{LoweringContext, SpecializationOutcome, graph, specialization};
use crate::plan::execution;
use crate::plan::execution::constant::{
ConstantId, ConstantProgram, ConstantTable, ConstantValue, ProfiledConstantProgram,
ProfiledConstantTable,
};
use crate::plan::module::ConstantInstantiation;
use std::collections::HashMap;
#[derive(Default)]
pub(super) struct ConstantLowering {
indices: HashMap<ConstantInstantiation, usize>,
owners: HashMap<ConstantLocation, SpecializationKey>,
table: ConstantTable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum ConstantFamily {
Int,
String,
BitArray,
Custom,
Float,
Bool,
Nil,
Tuple,
ParameterList,
ParameterListList,
IntList,
StringList,
BitArrayList,
UtfCodepointList,
CustomList,
ExternalList,
FloatList,
BoolList,
NilList,
TupleList,
ListList,
FunctionList,
Function,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct ConstantLocation {
family: ConstantFamily,
index: usize,
}
trait LoweredConstantValue: ConstantValue {
const FAMILY: ConstantFamily;
}
impl LoweredConstantValue for execution::graph::IntLocalId {
const FAMILY: ConstantFamily = ConstantFamily::Int;
}
impl LoweredConstantValue for execution::graph::StringLocalId {
const FAMILY: ConstantFamily = ConstantFamily::String;
}
impl LoweredConstantValue for execution::graph::BitArrayLocalId {
const FAMILY: ConstantFamily = ConstantFamily::BitArray;
}
impl LoweredConstantValue for execution::graph::CustomLocal {
const FAMILY: ConstantFamily = ConstantFamily::Custom;
}
impl LoweredConstantValue for execution::graph::FloatLocalId {
const FAMILY: ConstantFamily = ConstantFamily::Float;
}
impl LoweredConstantValue for execution::graph::BoolLocalId {
const FAMILY: ConstantFamily = ConstantFamily::Bool;
}
impl LoweredConstantValue for execution::graph::NilLocalId {
const FAMILY: ConstantFamily = ConstantFamily::Nil;
}
impl LoweredConstantValue for execution::graph::TupleLocalId {
const FAMILY: ConstantFamily = ConstantFamily::Tuple;
}
impl LoweredConstantValue for execution::graph::ParameterListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::ParameterList;
}
impl LoweredConstantValue for execution::graph::ParameterListListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::ParameterListList;
}
impl LoweredConstantValue for execution::graph::IntListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::IntList;
}
impl LoweredConstantValue for execution::graph::StringListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::StringList;
}
impl LoweredConstantValue for execution::graph::BitArrayListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::BitArrayList;
}
impl LoweredConstantValue for execution::graph::UtfCodepointListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::UtfCodepointList;
}
impl LoweredConstantValue for execution::graph::CustomListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::CustomList;
}
impl LoweredConstantValue for execution::graph::ExternalListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::ExternalList;
}
impl LoweredConstantValue for execution::graph::FloatListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::FloatList;
}
impl LoweredConstantValue for execution::graph::BoolListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::BoolList;
}
impl LoweredConstantValue for execution::graph::NilListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::NilList;
}
impl LoweredConstantValue for execution::graph::TupleListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::TupleList;
}
impl LoweredConstantValue for execution::graph::ListListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::ListList;
}
impl LoweredConstantValue for execution::graph::FunctionListLocalId {
const FAMILY: ConstantFamily = ConstantFamily::FunctionList;
}
impl LoweredConstantValue for execution::graph::FunctionLocal {
const FAMILY: ConstantFamily = ConstantFamily::Function;
}
impl ConstantLowering {
fn get<Return>(&self, key: &ConstantInstantiation) -> Option<ConstantId<Return>> {
self.indices.get(key).copied().map(ConstantId::new)
}
fn insert<Return: LoweredConstantValue>(
&mut self,
key: ConstantInstantiation,
owner: SpecializationKey,
program: ConstantProgram<Return>,
) -> ConstantId<Return> {
let id = self.table.push(program);
self.owners.insert(
ConstantLocation {
family: Return::FAMILY,
index: id.index(),
},
owner,
);
self.indices.insert(key, id.index());
id
}
pub(super) fn finish_plain(
mut self,
) -> SpecializationOutcome<ProfiledConstantTable<std::convert::Infallible>> {
let mut sealed = ProfiledConstantTable::default();
let mut outcome = SpecializationOutcome::Complete(());
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::IntLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::StringLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::BitArrayLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::CustomLocal>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::FloatLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::BoolLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::NilLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::TupleLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::ParameterListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::ParameterListListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::IntListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::StringListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::BitArrayListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::UtfCodepointListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::CustomListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::FloatListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::BoolListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::NilListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::TupleListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::ListListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::FunctionListLocalId>(&mut sealed),
|(), ()| (),
);
outcome = outcome.zip_with(
self.seal_plain_family::<execution::graph::FunctionLocal>(&mut sealed),
|(), ()| (),
);
outcome.map(|()| sealed)
}
pub(super) fn finish_hosted(self) -> ConstantTable {
self.table
}
fn seal_plain_family<Return>(
&mut self,
sealed: &mut ProfiledConstantTable<std::convert::Infallible>,
) -> SpecializationOutcome<()>
where
Return: LoweredConstantValue,
{
let programs = std::mem::take(Return::programs_mut(&mut self.table));
programs.into_iter().enumerate().fold(
SpecializationOutcome::Complete(()),
|outcome, (index, program)| {
let owner = self.owners[&ConstantLocation {
family: Return::FAMILY,
index,
}]
.clone();
outcome.zip_with(
SpecializationOutcome::from_representability(
seal_plain_constant_program(program),
owner,
),
|(), program| {
sealed.push(program);
},
)
},
)
}
}
fn seal_plain_constant_program<Return>(
program: ProfiledConstantProgram<Return, execution::function::HostedExecutionGraph>,
) -> specialization::Representability<ProfiledConstantProgram<Return, std::convert::Infallible>> {
let (block_graph, returns) = program.into_parts();
graph::seal_plain_block_graph(block_graph)
.map(|block_graph| ProfiledConstantProgram::from_parts(block_graph, returns.into_vec()))
}
impl LoweringContext {
fn lower_constant<ModuleValue, DraftValue, Return>(
&mut self,
instantiation: crate::plan::ConstantInstantiation,
materialize: impl FnOnce(&crate::plan::ConstantTemplates) -> ModuleValue,
lower: impl Copy
+ Fn(
&ModuleValue,
graph::DraftCursor,
&mut graph::DraftGraph,
&mut Self,
) -> specialization::Representability<graph::DraftFlow<DraftValue>>,
) -> specialization::Representability<execution::constant::ConstantId<Return>>
where
DraftValue: graph::DraftGraphValue + graph::FreezeGraphValue<Frozen = Return>,
Return: LoweredConstantValue,
{
let outer = self.substitution.to_module_substitution();
let key = instantiation.substitute(&outer);
if let Some(id) = self.constants.get(&key) {
return specialization::Representability::Inhabited(id);
}
let value = materialize(self.constant_templates.get(key.module()));
let owner = self.current_specialization.clone();
graph::lower_constant_graph(&value, self, lower)
.map(|program| self.constants.insert(key, owner, program))
}
pub(super) fn int_constant(
&mut self,
reference: &crate::plan::ConstantIntReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::IntLocalId>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_int(instantiation.clone()),
|templates| templates.materialize_int(&instantiation),
graph::int_expr,
)
}
pub(super) fn string_constant(
&mut self,
reference: &crate::plan::ConstantStringReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::StringLocalId>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_string(instantiation.clone()),
|templates| templates.materialize_string(&instantiation),
graph::string_expr,
)
}
pub(super) fn bit_array_constant(
&mut self,
reference: &crate::plan::ConstantBitArrayReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::BitArrayLocalId>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_bit_array(instantiation.clone()),
|templates| templates.materialize_bit_array(&instantiation),
graph::bit_array_expr,
)
}
pub(super) fn custom_constant(
&mut self,
reference: &crate::plan::ConstantCustomReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::CustomLocal>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_custom(instantiation.clone()),
|templates| templates.materialize_custom(&instantiation),
graph::custom_expr,
)
}
pub(super) fn float_constant(
&mut self,
reference: &crate::plan::ConstantFloatReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FloatLocalId>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_float(instantiation.clone()),
|templates| templates.materialize_float(&instantiation),
graph::float_expr,
)
}
pub(super) fn bool_constant(
&mut self,
reference: &crate::plan::ConstantBoolReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::BoolLocalId>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_bool(instantiation.clone()),
|templates| templates.materialize_bool(&instantiation),
graph::bool_expr,
)
}
pub(super) fn nil_constant(
&mut self,
reference: &crate::plan::ConstantNilReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::NilLocalId>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_nil(instantiation.clone()),
|templates| templates.materialize_nil(&instantiation),
graph::nil_expr,
)
}
pub(super) fn tuple_constant(
&mut self,
reference: &crate::plan::ConstantTupleReference,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::TupleLocalId>,
> {
let instantiation = reference.instantiation().clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_tuple(instantiation.clone()),
|templates| templates.materialize_tuple(&instantiation),
graph::tuple_expr,
)
}
pub(super) fn int_list_constant(
&mut self,
reference: &crate::plan::ConstantIntListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::IntListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Int(instantiation.clone()),
),
|templates| templates.materialize_int_list(&instantiation),
graph::int_list_expr,
)
}
pub(super) fn string_list_constant(
&mut self,
reference: &crate::plan::ConstantStringListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::StringListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::String(instantiation.clone()),
),
|templates| templates.materialize_string_list(&instantiation),
graph::string_list_expr,
)
}
pub(super) fn bit_array_list_constant(
&mut self,
reference: &crate::plan::ConstantBitArrayListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::BitArrayListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::BitArray(instantiation.clone()),
),
|templates| templates.materialize_bit_array_list(&instantiation),
graph::bit_array_list_expr,
)
}
pub(super) fn utf_codepoint_list_constant(
&mut self,
reference: &crate::plan::ConstantUtfCodepointListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::UtfCodepointListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::UtfCodepoint(instantiation.clone()),
),
|templates| templates.materialize_utf_codepoint_list(&instantiation),
graph::utf_codepoint_list_expr,
)
}
pub(super) fn custom_list_constant(
&mut self,
reference: &crate::plan::ConstantCustomListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::CustomListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Custom(instantiation.clone()),
),
|templates| templates.materialize_custom_list(&instantiation),
graph::custom_list_expr,
)
}
pub(super) fn external_list_constant(
&mut self,
reference: &crate::plan::ConstantExternalListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ExternalListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::External(instantiation.clone()),
),
|templates| templates.materialize_external_list(&instantiation),
graph::external_list_expr,
)
}
pub(super) fn float_list_constant(
&mut self,
reference: &crate::plan::ConstantFloatListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FloatListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Float(instantiation.clone()),
),
|templates| templates.materialize_float_list(&instantiation),
graph::float_list_expr,
)
}
pub(super) fn bool_list_constant(
&mut self,
reference: &crate::plan::ConstantBoolListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::BoolListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Bool(instantiation.clone()),
),
|templates| templates.materialize_bool_list(&instantiation),
graph::bool_list_expr,
)
}
pub(super) fn nil_list_constant(
&mut self,
reference: &crate::plan::ConstantNilListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::NilListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Nil(instantiation.clone()),
),
|templates| templates.materialize_nil_list(&instantiation),
graph::nil_list_expr,
)
}
pub(super) fn tuple_list_constant(
&mut self,
reference: &crate::plan::ConstantTupleListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::TupleListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Tuple(instantiation.clone()),
),
|templates| templates.materialize_tuple_list(&instantiation),
graph::tuple_list_expr,
)
}
pub(super) fn parameter_list_list_constant(
&mut self,
reference: &crate::plan::ConstantParameterListListInstantiation,
_parameter: crate::plan::TypeParameterId,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ParameterListListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::ParameterList(instantiation.clone()),
),
|templates| templates.materialize_parameter_list_list(&instantiation),
|expression, cursor, graph, context| {
graph::parameter_list_list_expr(expression, cursor, graph, context).map(|flow| {
flow.map(|value| graph::DraftParameterListList::new(value.into_list()))
})
},
)
}
pub(super) fn list_list_constant(
&mut self,
reference: &crate::plan::ConstantListListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ListListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::List(instantiation.clone()),
),
|templates| templates.materialize_list_list(&instantiation),
graph::list_list_expr,
)
}
pub(super) fn function_list_constant(
&mut self,
reference: &crate::plan::ConstantFunctionListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Function(instantiation.clone()),
),
|templates| templates.materialize_function_list(&instantiation),
graph::function_list_expr,
)
}
fn lower_generic_list_constant<DraftValue, Value>(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
wrap: impl Copy + Fn(graph::DraftList) -> DraftValue,
) -> specialization::Representability<execution::constant::ConstantId<Value>>
where
DraftValue: graph::DraftGraphValue + graph::FreezeGraphValue<Frozen = Value>,
Value: LoweredConstantValue,
{
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_list(&instantiation),
|expression, cursor, graph, context| {
graph::generic_list_expr(expression, cursor, graph, context)
.map(|flow| flow.map(wrap))
},
)
}
pub(super) fn generic_parameter_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
_parameter: crate::plan::TypeParameterId,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ParameterListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftParameterList::new)
}
pub(super) fn generic_int_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::IntListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftIntList::new)
}
pub(super) fn generic_string_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::StringListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftStringList::new)
}
pub(super) fn generic_bit_array_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::BitArrayListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftBitArrayList::new)
}
pub(super) fn generic_utf_codepoint_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::UtfCodepointListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftUtfCodepointList::new)
}
pub(super) fn generic_custom_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
_shape: &SpecializedCustomValueShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::CustomListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftCustomList::new)
}
pub(super) fn generic_external_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
_shape: &specialization::SpecializedExternalValueShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ExternalListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftExternalList::new)
}
pub(super) fn generic_float_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FloatListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftFloatList::new)
}
pub(super) fn generic_bool_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::BoolListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftBoolList::new)
}
pub(super) fn generic_nil_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::NilListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftNilList::new)
}
pub(super) fn generic_tuple_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
_elements: &[SpecializedValueShape],
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::TupleListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftTupleList::new)
}
pub(super) fn generic_parameter_list_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
_parameter: crate::plan::TypeParameterId,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ParameterListListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftParameterListList::new)
}
pub(super) fn generic_list_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
_item_shape: &specialization::StoredValueShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ListListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftListList::new)
}
pub(super) fn generic_function_list_constant(
&mut self,
reference: &crate::plan::ConstantGenericListInstantiation,
_shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionListLocalId>,
> {
self.lower_generic_list_constant(reference, graph::DraftFunctionList::new)
}
pub(super) fn parameter_list_list_as_stored_constant(
&mut self,
reference: &crate::plan::ConstantParameterListListInstantiation,
_item_shape: &specialization::StoredValueShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::ListListLocalId>,
> {
let instantiation = reference.clone();
self.lower_constant(
crate::plan::ConstantInstantiation::from_list(
crate::plan::ConstantListInstantiation::ParameterList(instantiation.clone()),
),
|templates| templates.materialize_parameter_list_list(&instantiation),
|expression, cursor, graph, context| {
graph::parameter_list_list_expr(expression, cursor, graph, context)
.map(|flow| flow.map(|value| graph::DraftListList::new(value.into_list())))
},
)
}
fn lower_function_constant<ModuleValue, DraftValue>(
&mut self,
instantiation: crate::plan::ConstantInstantiation,
materialize: impl FnOnce(&crate::plan::ConstantTemplates) -> ModuleValue,
lower: impl Copy
+ Fn(
&ModuleValue,
graph::DraftCursor,
&mut graph::DraftGraph,
&mut Self,
) -> specialization::Representability<graph::DraftFlow<DraftValue>>,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
>
where
DraftValue: graph::DraftFunctionValue,
{
let outer = self.substitution.to_module_substitution();
let key = instantiation.substitute(&outer);
if let Some(id) = self.constants.get(&key) {
return specialization::Representability::Inhabited(id);
}
let value = materialize(self.constant_templates.get(key.module()));
let owner = self.current_specialization.clone();
graph::lower_constant_graph(&value, self, |expression, cursor, graph, context| {
lower(expression, cursor, graph, context)
.map(|flow| flow.map(graph::DraftFunctionValue::into_function))
})
.map(|program| self.constants.insert(key, owner, program))
}
pub(super) fn generic_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_generic_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn generic_never_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_function(&instantiation),
|expression, cursor, graph, context| {
graph::generic_never_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn custom_never_function_constant(
&mut self,
reference: &crate::plan::ConstantCustomFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Custom(instantiation.clone()),
),
|templates| templates.materialize_custom_function(&instantiation),
graph::custom_never_function_expr,
)
}
pub(super) fn tuple_never_function_constant(
&mut self,
reference: &crate::plan::ConstantTupleFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Tuple(instantiation.clone()),
),
|templates| templates.materialize_tuple_function(&instantiation),
graph::tuple_never_function_expr,
)
}
pub(super) fn generic_int_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(reference, shape, graph::generic_int_function_expr)
}
pub(super) fn generic_float_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(reference, shape, graph::generic_float_function_expr)
}
pub(super) fn generic_string_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(reference, shape, graph::generic_string_function_expr)
}
pub(super) fn generic_bit_array_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(
reference,
shape,
graph::generic_bit_array_function_expr,
)
}
pub(super) fn generic_utf_codepoint_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(
reference,
shape,
graph::generic_utf_codepoint_function_expr,
)
}
pub(super) fn generic_bool_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(reference, shape, graph::generic_bool_function_expr)
}
pub(super) fn generic_nil_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(reference, shape, graph::generic_nil_function_expr)
}
pub(super) fn generic_tuple_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
self.generic_typed_function_constant(reference, shape, graph::generic_tuple_function_expr)
}
fn generic_typed_function_constant<DraftValue>(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
shape: &SpecializedFunctionShape,
lower: impl Copy
+ Fn(
&crate::plan::GenericFunctionExpr,
&SpecializedFunctionShape,
graph::DraftCursor,
&mut graph::DraftGraph,
&mut Self,
) -> specialization::Representability<graph::DraftFlow<DraftValue>>,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
>
where
DraftValue: graph::DraftFunctionValue,
{
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_function(&instantiation),
|expression, cursor, graph, context| lower(expression, shape, cursor, graph, context),
)
}
pub(super) fn generic_custom_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
return_shape: &SpecializedCustomValueShape,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_function(&instantiation),
|expression, cursor, graph, context| {
graph::generic_custom_function_expr(
expression,
return_shape,
shape,
cursor,
graph,
context,
)
},
)
}
pub(super) fn generic_external_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
return_shape: &specialization::SpecializedExternalValueShape,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_function(&instantiation),
|expression, cursor, graph, context| {
graph::generic_external_function_expr(
expression,
return_shape,
shape,
cursor,
graph,
context,
)
},
)
}
pub(super) fn generic_list_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
item_shape: &SpecializedValueShape,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_function(&instantiation),
|expression, cursor, graph, context| {
graph::generic_list_function_expr(
expression, item_shape, shape, cursor, graph, context,
)
},
)
}
pub(super) fn generic_function_function_constant(
&mut self,
reference: &crate::plan::ConstantGenericFunctionInstantiation,
return_shape: &SpecializedFunctionShape,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Generic(instantiation.clone()),
),
|templates| templates.materialize_generic_function(&instantiation),
|expression, cursor, graph, context| {
graph::generic_function_function_expr(
expression,
return_shape,
shape,
cursor,
graph,
context,
)
},
)
}
pub(super) fn symbolic_custom_function_constant(
&mut self,
reference: &crate::plan::ConstantCustomFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Custom(instantiation.clone()),
),
|templates| templates.materialize_custom_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_custom_function_expr_kind(
expression.kind(),
shape,
cursor,
graph,
context,
)
},
)
}
pub(super) fn symbolic_external_function_constant(
&mut self,
reference: &crate::plan::ConstantExternalFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::External(instantiation.clone()),
),
|templates| templates.materialize_external_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_external_function_expr_kind(
expression.kind(),
shape,
cursor,
graph,
context,
)
},
)
}
pub(super) fn symbolic_list_function_constant(
&mut self,
reference: &crate::plan::ConstantListFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::List(instantiation.clone()),
),
|templates| templates.materialize_list_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_list_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn symbolic_function_function_constant(
&mut self,
reference: &crate::plan::ConstantFunctionFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Function(instantiation.clone()),
),
|templates| templates.materialize_function_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_function_function_expr_kind(
expression.kind(),
shape,
cursor,
graph,
context,
)
},
)
}
pub(super) fn symbolic_int_function_constant(
&mut self,
reference: &crate::plan::ConstantIntFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Int(instantiation.clone()),
),
|templates| templates.materialize_int_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_int_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn symbolic_float_function_constant(
&mut self,
reference: &crate::plan::ConstantFloatFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Float(instantiation.clone()),
),
|templates| templates.materialize_float_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_float_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn symbolic_string_function_constant(
&mut self,
reference: &crate::plan::ConstantStringFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::String(instantiation.clone()),
),
|templates| templates.materialize_string_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_string_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn symbolic_bit_array_function_constant(
&mut self,
reference: &crate::plan::ConstantBitArrayFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::BitArray(instantiation.clone()),
),
|templates| templates.materialize_bit_array_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_bit_array_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn symbolic_utf_codepoint_function_constant(
&mut self,
reference: &crate::plan::ConstantUtfCodepointFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::UtfCodepoint(instantiation.clone()),
),
|templates| templates.materialize_utf_codepoint_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_utf_codepoint_function_expr(
expression, shape, cursor, graph, context,
)
},
)
}
pub(super) fn symbolic_bool_function_constant(
&mut self,
reference: &crate::plan::ConstantBoolFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Bool(instantiation.clone()),
),
|templates| templates.materialize_bool_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_bool_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn symbolic_nil_function_constant(
&mut self,
reference: &crate::plan::ConstantNilFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Nil(instantiation.clone()),
),
|templates| templates.materialize_nil_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_nil_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn symbolic_tuple_function_constant(
&mut self,
reference: &crate::plan::ConstantTupleFunctionInstantiation,
shape: &SpecializedFunctionShape,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Tuple(instantiation.clone()),
),
|templates| templates.materialize_tuple_function(&instantiation),
|expression, cursor, graph, context| {
graph::symbolic_tuple_function_expr(expression, shape, cursor, graph, context)
},
)
}
pub(super) fn int_function_constant(
&mut self,
reference: &crate::plan::ConstantIntFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Int(instantiation.clone()),
),
|templates| templates.materialize_int_function(&instantiation),
graph::int_function_expr,
)
}
pub(super) fn float_function_constant(
&mut self,
reference: &crate::plan::ConstantFloatFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Float(instantiation.clone()),
),
|templates| templates.materialize_float_function(&instantiation),
graph::float_function_expr,
)
}
pub(super) fn string_function_constant(
&mut self,
reference: &crate::plan::ConstantStringFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::String(instantiation.clone()),
),
|templates| templates.materialize_string_function(&instantiation),
graph::string_function_expr,
)
}
pub(super) fn bit_array_function_constant(
&mut self,
reference: &crate::plan::ConstantBitArrayFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::BitArray(instantiation.clone()),
),
|templates| templates.materialize_bit_array_function(&instantiation),
graph::bit_array_function_expr,
)
}
pub(super) fn utf_codepoint_function_constant(
&mut self,
reference: &crate::plan::ConstantUtfCodepointFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::UtfCodepoint(instantiation.clone()),
),
|templates| templates.materialize_utf_codepoint_function(&instantiation),
graph::utf_codepoint_function_expr,
)
}
pub(super) fn custom_function_constant(
&mut self,
reference: &crate::plan::ConstantCustomFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Custom(instantiation.clone()),
),
|templates| templates.materialize_custom_function(&instantiation),
graph::custom_function_expr,
)
}
pub(super) fn external_function_constant(
&mut self,
reference: &crate::plan::ConstantExternalFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::External(instantiation.clone()),
),
|templates| templates.materialize_external_function(&instantiation),
graph::external_function_expr,
)
}
pub(super) fn bool_function_constant(
&mut self,
reference: &crate::plan::ConstantBoolFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Bool(instantiation.clone()),
),
|templates| templates.materialize_bool_function(&instantiation),
graph::bool_function_expr,
)
}
pub(super) fn nil_function_constant(
&mut self,
reference: &crate::plan::ConstantNilFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Nil(instantiation.clone()),
),
|templates| templates.materialize_nil_function(&instantiation),
graph::nil_function_expr,
)
}
pub(super) fn tuple_function_constant(
&mut self,
reference: &crate::plan::ConstantTupleFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Tuple(instantiation.clone()),
),
|templates| templates.materialize_tuple_function(&instantiation),
graph::tuple_function_expr,
)
}
pub(super) fn list_function_constant(
&mut self,
reference: &crate::plan::ConstantListFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::List(instantiation.clone()),
),
|templates| templates.materialize_list_function(&instantiation),
graph::list_function_expr,
)
}
pub(super) fn function_function_constant(
&mut self,
reference: &crate::plan::ConstantFunctionFunctionInstantiation,
) -> specialization::Representability<
execution::constant::ConstantId<execution::graph::FunctionLocal>,
> {
let instantiation = reference.clone();
self.lower_function_constant(
crate::plan::ConstantInstantiation::from_function(
crate::plan::ConstantFunctionInstantiation::Function(instantiation.clone()),
),
|templates| templates.materialize_function_function(&instantiation),
graph::function_function_expr,
)
}
}
#[cfg(test)]
mod tests {
use super::{ConstantFamily, ConstantLocation, ConstantLowering, LoweredConstantValue};
use crate::plan::execution::ExecutionPlan;
use crate::plan::execution::constant::{ConstantId, ConstantValue, ProfiledConstantProgram};
use crate::plan::execution::function::{
ExecutionGraphProfile, ExternalFunctionId, FunctionReturnFamily, HostedExecutionGraph,
};
use crate::plan::execution::graph::{
BitArrayListLocalId, BitArrayLocalId, BlockGraphExitId, BlockId, BoolListLocalId,
BoolLocalId, CustomListLocalId, CustomLocal, ExternalFunctionInstruction,
ExternalFunctionInstructionKind, ExternalFunctionInstructionView, ExternalFunctionLocal,
ExternalFunctionLocalId, ExternalFunctionTarget, ExternalListLocalId, FloatListLocalId,
FloatLocalId, FunctionListLocalId, FunctionLocal, IntInstruction, IntListLocalId,
IntLocalId, ListListLocalId, NilListLocalId, NilLocalId, ParamLocal, ParamSlot,
ParameterListListLocalId, ParameterListLocalId, ProfiledBlock, ProfiledBlockGraph,
ProfiledInstruction, ProfiledInstructionKind, SourceStop, SourceStopKind,
StringListLocalId, StringLocalId, Terminator, TupleListLocalId, TupleLocalId,
UtfCodepointListLocalId,
};
use crate::plan::execution::lowering::specialization::SpecializationKey;
use crate::plan::execution::type_::{
ExternalFunctionType, ExternalTypeId, FunctionType, ValueShapeId, ValueType,
};
use num_bigint::BigInt;
use std::collections::HashSet;
#[test]
fn constant_entry_is_a_reusable_zero_argument_typed_graph_program() {
let plan = execution_plan("const one = 1 pub fn main() { one + one }");
let program = plan.constant(ConstantId::<IntLocalId>::new(0));
let block_graph = program.block_graph();
assert_eq!(block_graph.entry(), BlockId::new(0));
assert_eq!(block_graph.blocks().len(), 1);
let block = block_graph.block(BlockId::new(0));
assert!(block.params().is_empty());
assert_eq!(block.instructions().len(), 1);
let instruction = &block.instructions()[0];
assert_eq!(
instruction.output().local(),
&ParamLocal::Int(IntLocalId(0))
);
assert_eq!(int_literal(instruction), &1.into());
assert_eq!(returned_int(program, block.terminator()), IntLocalId(0));
let main = plan.int_function(crate::plan::execution::function::IntFunctionId(0));
let block = main.body().block_graph().block(BlockId::new(0));
assert_eq!(block.instructions().len(), 3);
for (index, instruction) in block.instructions()[..2].iter().enumerate() {
let output = IntLocalId(index);
assert_eq!(instruction.output().local(), &ParamLocal::Int(output));
assert_eq!(int_constant(instruction), ConstantId::new(0));
}
}
#[test]
fn constant_return_types_select_every_independent_table_family() {
fn family<Return: LoweredConstantValue>() -> ConstantFamily {
Return::FAMILY
}
assert_eq!(
[
family::<IntLocalId>(),
family::<StringLocalId>(),
family::<BitArrayLocalId>(),
family::<CustomLocal>(),
family::<FloatLocalId>(),
family::<BoolLocalId>(),
family::<NilLocalId>(),
family::<TupleLocalId>(),
family::<ParameterListLocalId>(),
family::<ParameterListListLocalId>(),
family::<IntListLocalId>(),
family::<StringListLocalId>(),
family::<BitArrayListLocalId>(),
family::<UtfCodepointListLocalId>(),
family::<CustomListLocalId>(),
family::<ExternalListLocalId>(),
family::<FloatListLocalId>(),
family::<BoolListLocalId>(),
family::<NilListLocalId>(),
family::<TupleListLocalId>(),
family::<ListListLocalId>(),
family::<FunctionListLocalId>(),
family::<FunctionLocal>(),
],
[
ConstantFamily::Int,
ConstantFamily::String,
ConstantFamily::BitArray,
ConstantFamily::Custom,
ConstantFamily::Float,
ConstantFamily::Bool,
ConstantFamily::Nil,
ConstantFamily::Tuple,
ConstantFamily::ParameterList,
ConstantFamily::ParameterListList,
ConstantFamily::IntList,
ConstantFamily::StringList,
ConstantFamily::BitArrayList,
ConstantFamily::UtfCodepointList,
ConstantFamily::CustomList,
ConstantFamily::ExternalList,
ConstantFamily::FloatList,
ConstantFamily::BoolList,
ConstantFamily::NilList,
ConstantFamily::TupleList,
ConstantFamily::ListList,
ConstantFamily::FunctionList,
ConstantFamily::Function,
]
);
}
#[test]
fn repeated_instantiations_deduplicate_with_family_local_ids() {
let source = r#"
const one = 1
const two = 2
const label = "selected"
pub fn main() {
#(one, one, two, label, label)
}
"#;
let plan = execution_plan(source);
let constants = &plan.program.common.constants;
assert_eq!(<IntLocalId as ConstantValue>::programs(constants).len(), 2);
assert_eq!(
<StringLocalId as ConstantValue>::programs(constants).len(),
1
);
let main = plan.tuple_function(crate::plan::execution::function::TupleFunctionId(0));
let instructions = main.body().block_graph().blocks()[0].instructions();
assert_eq!(
instructions[..3]
.iter()
.map(int_constant)
.collect::<Vec<_>>(),
vec![ConstantId::new(0), ConstantId::new(0), ConstantId::new(1)]
);
assert_eq!(
instructions[3..5]
.iter()
.map(string_constant)
.collect::<Vec<_>>(),
vec![ConstantId::new(0), ConstantId::new(0)]
);
}
#[test]
fn function_constant_specializations_preserve_concrete_symbolic_and_never_representations() {
let sources = [
r#"
fn identity(value: value) { value }
const selected = identity
pub fn main() { selected(1) }
"#,
r#"
pub type Never
fn selected(_value: Never) { 1 }
const selected_constant = selected
pub fn main() { selected_constant }
"#,
r#"
pub type Never
fn selected(_value: Int) -> Never { panic as "never" }
const selected_constant = selected
pub fn main() { selected_constant }
"#,
];
let plans = sources.map(execution_plan);
assert_eq!(
returned_int_function_constant(&plans[0]),
crate::plan::execution::graph::IntFunctionLocalId(0)
);
assert_eq!(
returned_generic_function_constant(&plans[1]),
crate::plan::execution::graph::GenericFunctionLocalId(0)
);
assert_eq!(
returned_never_function_constant(&plans[2]),
crate::plan::execution::graph::NeverFunctionLocalId(0)
);
}
#[test]
fn constant_profile_completion_retains_hosted_external_nodes_and_erases_plain_owners() {
let owner = SpecializationKey::monomorphic(crate::plan::FunctionTemplateId::new(3));
let hosted = external_constant_lowering(owner.clone()).finish_hosted();
let program = hosted.get(ConstantId::<FunctionLocal>::new(0));
let graph = program.block_graph();
let block = graph.block(graph.entry());
assert_eq!(
external_function_local(returned_function(program, block.terminator())),
ExternalFunctionLocalId(0)
);
assert_eq!(
external_function_reference(&block.instructions()[0]),
ExternalFunctionId::new(2, ExternalTypeId::new(0))
);
assert_eq!(
external_constant_lowering(owner.clone())
.finish_plain()
.erased_specializations(),
HashSet::from([owner])
);
}
#[test]
#[should_panic(expected = "constant fixture should contain an Int literal")]
fn int_literal_guard_rejects_other_instructions() {
let plan = execution_plan("const one = 1 pub fn main() { one }");
let graph = plan
.int_function(crate::plan::execution::function::IntFunctionId(0))
.body()
.block_graph();
int_literal(&graph.block(graph.entry()).instructions()[0]);
}
#[test]
#[should_panic(expected = "constant fixture should return an Int local")]
fn returned_int_guard_rejects_other_terminators() {
let plan = execution_plan("const one = 1 pub fn main() { one }");
let program = plan.constant(ConstantId::<IntLocalId>::new(0));
returned_int(
program,
&Terminator::SourceStop(SourceStop::new(
SourceStopKind::Panic,
None,
crate::plan::PanicSite::unknown(),
)),
);
}
#[test]
#[should_panic(expected = "constant fixture should return a function local")]
fn returned_plain_function_guard_rejects_other_terminators() {
let plan = execution_plan(
r#"
fn identity(value: value) { value }
const selected = identity
pub fn main() { selected(1) }
"#,
);
let program = plan.constant(ConstantId::<FunctionLocal>::new(0));
returned_function(
program,
&Terminator::SourceStop(SourceStop::new(
SourceStopKind::Panic,
None,
crate::plan::PanicSite::unknown(),
)),
);
}
#[test]
#[should_panic(expected = "constant fixture should return a function local")]
fn returned_hosted_function_guard_rejects_other_terminators() {
let owner = SpecializationKey::monomorphic(crate::plan::FunctionTemplateId::new(3));
let hosted = external_constant_lowering(owner).finish_hosted();
let program = hosted.get(ConstantId::<FunctionLocal>::new(0));
returned_function(
program,
&Terminator::SourceStop(SourceStop::new(
SourceStopKind::Panic,
None,
crate::plan::PanicSite::unknown(),
)),
);
}
#[test]
#[should_panic(expected = "constant fixture should reference an Int constant")]
fn int_constant_guard_rejects_other_instructions() {
let plan = execution_plan("const one = 1 pub fn main() { one }");
let graph = plan
.constant(ConstantId::<IntLocalId>::new(0))
.block_graph();
int_constant(&graph.block(graph.entry()).instructions()[0]);
}
#[test]
#[should_panic(expected = "constant fixture should reference a String constant")]
fn string_constant_guard_rejects_other_instructions() {
let plan = execution_plan("const one = 1 pub fn main() { one }");
let graph = plan
.constant(ConstantId::<IntLocalId>::new(0))
.block_graph();
string_constant(&graph.block(graph.entry()).instructions()[0]);
}
#[test]
#[should_panic(expected = "constant fixture should return an Int function local")]
fn int_function_constant_guard_rejects_symbolic_functions() {
let plan = execution_plan(
r#"
pub type Never
fn selected(_value: Never) { 1 }
const selected_constant = selected
pub fn main() { selected_constant }
"#,
);
returned_int_function_constant(&plan);
}
#[test]
#[should_panic(expected = "constant fixture should return a generic function local")]
fn generic_function_constant_guard_rejects_concrete_functions() {
let plan = execution_plan(
r#"
fn identity(value: value) { value }
const selected = identity
pub fn main() { selected(1) }
"#,
);
returned_generic_function_constant(&plan);
}
#[test]
#[should_panic(expected = "constant fixture should return a never function local")]
fn never_function_constant_guard_rejects_concrete_functions() {
let plan = execution_plan(
r#"
fn identity(value: value) { value }
const selected = identity
pub fn main() { selected(1) }
"#,
);
returned_never_function_constant(&plan);
}
#[test]
#[should_panic(expected = "constant fixture should return an external function local")]
fn external_function_constant_guard_rejects_concrete_functions() {
let plan = execution_plan(
r#"
fn identity(value: value) { value }
const selected = identity
pub fn main() { selected(1) }
"#,
);
external_function_local(returned_function_constant(&plan));
}
#[test]
#[should_panic(expected = "constant fixture should reference an external function")]
fn external_function_reference_guard_rejects_other_instructions() {
external_function_reference(&ProfiledInstruction::<HostedExecutionGraph>::new(
ParamSlot::new(ParamLocal::Int(IntLocalId(0)), ValueShapeId::new(0)),
ProfiledInstructionKind::Int(IntInstruction::Value(1.into())),
));
}
#[test]
#[should_panic(expected = "constant fixture should reference an external function")]
fn external_function_reference_guard_rejects_other_external_instruction_kinds() {
let (_, instruction) =
external_function_instruction(ExternalFunctionInstructionKind::Closure {
target: ExternalFunctionTarget::Value(ExternalFunctionId::new(
2,
ExternalTypeId::new(0),
)),
captures: Box::new([]),
});
external_function_reference(&instruction);
}
fn int_literal<Graph: ExecutionGraphProfile>(
instruction: &ProfiledInstruction<Graph>,
) -> &BigInt {
match instruction.kind() {
ProfiledInstructionKind::Int(IntInstruction::Value(value)) => value,
_ => panic!("constant fixture should contain an Int literal"),
}
}
fn returned_int<Graph: ExecutionGraphProfile>(
program: &crate::plan::execution::constant::ProfiledConstantProgram<IntLocalId, Graph>,
terminator: &Terminator,
) -> IntLocalId {
match terminator {
Terminator::Exit(exit) => *program.return_(*exit),
_ => panic!("constant fixture should return an Int local"),
}
}
fn returned_function<'a, Graph: ExecutionGraphProfile>(
program: &'a crate::plan::execution::constant::ProfiledConstantProgram<
FunctionLocal,
Graph,
>,
terminator: &Terminator,
) -> &'a FunctionLocal {
match terminator {
Terminator::Exit(exit) => program.return_(*exit),
_ => panic!("constant fixture should return a function local"),
}
}
fn returned_int_function_constant(
plan: &ExecutionPlan,
) -> crate::plan::execution::graph::IntFunctionLocalId {
match returned_function_constant(plan) {
FunctionLocal::Int(local) => *local,
_ => panic!("constant fixture should return an Int function local"),
}
}
fn returned_generic_function_constant(
plan: &ExecutionPlan,
) -> crate::plan::execution::graph::GenericFunctionLocalId {
match returned_function_constant(plan) {
FunctionLocal::Generic(local) => local.id(),
_ => panic!("constant fixture should return a generic function local"),
}
}
fn returned_never_function_constant(
plan: &ExecutionPlan,
) -> crate::plan::execution::graph::NeverFunctionLocalId {
match returned_function_constant(plan) {
FunctionLocal::Never(local) => local.id(),
_ => panic!("constant fixture should return a never function local"),
}
}
fn returned_function_constant(plan: &ExecutionPlan) -> &FunctionLocal {
let program = plan.constant(ConstantId::<FunctionLocal>::new(0));
let graph = program.block_graph();
returned_function(program, graph.block(graph.entry()).terminator())
}
fn external_function_local(local: &FunctionLocal) -> ExternalFunctionLocalId {
match local {
FunctionLocal::External(local) => local.id(),
_ => panic!("constant fixture should return an external function local"),
}
}
fn external_function_reference(
instruction: &ProfiledInstruction<HostedExecutionGraph>,
) -> ExternalFunctionId {
match instruction.kind() {
ProfiledInstructionKind::ExternalFunction(instruction) => {
match instruction.instruction().kind() {
ExternalFunctionInstructionKind::Reference(ExternalFunctionTarget::Value(
function,
)) => *function,
_ => panic!("constant fixture should reference an external function"),
}
}
_ => panic!("constant fixture should reference an external function"),
}
}
fn external_constant_lowering(owner: SpecializationKey) -> ConstantLowering {
let (local, instruction) =
external_function_instruction(ExternalFunctionInstructionKind::Reference(
ExternalFunctionTarget::Value(ExternalFunctionId::new(2, ExternalTypeId::new(0))),
));
let program = ProfiledConstantProgram::from_parts(
ProfiledBlockGraph::<HostedExecutionGraph>::from_parts(
BlockId::new(0),
vec![ProfiledBlock::new(
Vec::new(),
vec![instruction],
Terminator::Exit(BlockGraphExitId::new(0)),
)],
),
vec![FunctionLocal::External(local)],
);
let mut lowering = ConstantLowering::default();
let id = lowering.table.push(program);
lowering.owners.insert(
ConstantLocation {
family: ConstantFamily::Function,
index: id.index(),
},
owner,
);
lowering
}
fn external_function_instruction(
kind: ExternalFunctionInstructionKind,
) -> (
ExternalFunctionLocal,
ProfiledInstruction<HostedExecutionGraph>,
) {
let external_type = ExternalTypeId::new(0);
let function_type = FunctionType::new(Vec::new(), ValueType::External(external_type));
let external_function_type =
ExternalFunctionType::from_shapes(function_type.clone(), Vec::new(), external_type);
let local = ExternalFunctionLocal::new(ExternalFunctionLocalId(0), external_function_type);
let instruction = ProfiledInstruction::new(
ParamSlot::new(
ParamLocal::ExternalFunction(local.clone()),
ValueShapeId::new(0),
),
ProfiledInstructionKind::ExternalFunction(ExternalFunctionInstruction::new(
function_type,
FunctionReturnFamily::External,
kind,
)),
);
(local, instruction)
}
fn int_constant<Graph: ExecutionGraphProfile>(
instruction: &ProfiledInstruction<Graph>,
) -> ConstantId<IntLocalId> {
match instruction.kind() {
ProfiledInstructionKind::Int(IntInstruction::Constant(id)) => *id,
_ => panic!("constant fixture should reference an Int constant"),
}
}
fn string_constant<Graph: ExecutionGraphProfile>(
instruction: &ProfiledInstruction<Graph>,
) -> ConstantId<StringLocalId> {
match instruction.kind() {
ProfiledInstructionKind::String(
crate::plan::execution::graph::StringInstruction::Constant(id),
) => *id,
_ => panic!("constant fixture should reference a String constant"),
}
}
fn execution_plan(source: &str) -> ExecutionPlan {
let typed = crate::compile_typed_module("main", "main.gleam", source)
.expect("source should compile");
let module_plan = crate::plan_module(typed).expect("source should plan");
ExecutionPlan::from_module_plan(module_plan)
}
}