use std::collections::HashMap;
use source_map::SpanWithSource;
use crate::{
behavior::functions::{ClassPropertiesToRegister, FunctionBehavior},
context::{environment::FunctionScope, ContextType},
events::{Event, RootReference},
CheckingData, Facts, FunctionId, GenericTypeParameters, Scope, Type, TypeId,
};
use super::{classes::register_properties_into_environment, TypeStore};
#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
pub struct FunctionType {
pub id: FunctionId,
pub constant_function: Option<String>,
pub behavior: FunctionBehavior,
pub type_parameters: Option<GenericTypeParameters>,
pub parameters: SynthesisedParameters,
pub return_type: TypeId,
pub effects: Vec<Event>,
pub free_variables: HashMap<RootReference, TypeId>,
pub closed_over_variables: HashMap<RootReference, TypeId>,
}
impl FunctionType {
pub(crate) fn new_auto_constructor<
T: crate::ReadFromFS,
A: crate::ASTImplementation,
S: ContextType,
>(
class_prototype: TypeId,
properties: ClassPropertiesToRegister<A>,
context: &mut crate::context::Context<S>,
checking_data: &mut CheckingData<T, A>,
) -> Self {
let scope = Scope::Function(FunctionScope::Constructor {
extends: false,
type_of_super: None,
this_object_type: TypeId::ERROR_TYPE,
});
let (on, env_data, _) = context.new_lexical_environment_fold_into_parent(
scope,
checking_data,
|environment, checking_data| {
let on = create_this_before_function_synthesis(
&mut checking_data.types,
&mut environment.facts,
class_prototype,
);
if let Scope::Function(FunctionScope::Constructor {
ref mut this_object_type,
..
}) = environment.context_type.scope
{
*this_object_type = on;
}
register_properties_into_environment(environment, on, checking_data, properties);
on
},
);
let behavior =
FunctionBehavior::Constructor { non_super_prototype: None, this_object_type: on };
let (facts, _free_variables) = env_data.unwrap();
Self {
id: crate::FunctionId::AUTO_CONSTRUCTOR,
constant_function: None,
type_parameters: None,
parameters: SynthesisedParameters::default(),
return_type: on,
effects: facts.events,
behavior,
free_variables: Default::default(),
closed_over_variables: Default::default(),
}
}
}
pub(crate) fn create_this_before_function_synthesis(
types: &mut TypeStore,
facts: &mut Facts,
prototype: TypeId,
) -> TypeId {
let ty = types.register_type(Type::Object(crate::types::ObjectNature::RealDeal));
crate::utils::notify!("Registered 'this' type as {:?}", ty);
let value = Event::CreateObject {
referenced_in_scope_as: ty,
prototype: crate::events::PrototypeArgument::Yeah(prototype),
position: None,
is_function_this: true,
};
facts.events.push(value);
ty
}
#[derive(Clone, Copy, Debug, binary_serialize_derive::BinarySerializable)]
pub enum GetSet {
Get,
Set,
}
#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
pub struct SynthesisedParameter {
pub name: String,
pub ty: TypeId,
pub position: SpanWithSource,
pub missing_value: Option<TypeId>,
}
#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
pub struct SynthesisedRestParameter {
pub name: String,
pub item_type: TypeId,
pub position: SpanWithSource,
}
#[derive(Clone, Debug, Default, binary_serialize_derive::BinarySerializable)]
pub struct SynthesisedParameters {
pub parameters: Vec<SynthesisedParameter>,
pub rest_parameter: Option<SynthesisedRestParameter>,
}
impl SynthesisedParameters {
pub(crate) fn get_type_constraint_at_index(&self, idx: usize) -> Option<TypeId> {
if let Some(param) = self.parameters.get(idx) {
Some(param.ty)
} else {
self.rest_parameter.as_ref().map(|rest| rest.item_type)
}
}
}
#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
#[non_exhaustive]
pub enum SynthesisedArgument {
NonSpread { ty: TypeId, position: SpanWithSource },
}
impl SynthesisedArgument {
pub(crate) fn get_position(&self) -> SpanWithSource {
match self {
SynthesisedArgument::NonSpread { ty: _, position } => *position,
}
}
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn to_type(&self) -> Result<TypeId, ()> {
match self {
SynthesisedArgument::NonSpread { ty, position: _ } => Ok(*ty),
}
}
}