use crate::context::Context;
use crate::error::{ErrKind, Error};
use crate::generics::{self, GenericExpander, GenericMap, GenericUser};
use crate::instance::{Name, ObjectInstance};
use crate::instruction::{InstrKind, Instruction, TypeDec, VarAssign};
use crate::location::SpanTuple;
use crate::symbol::Symbol;
use crate::typechecker::{CheckedType, SpecializedNode, TypeCheck, TypeCtx, TypeId};
use std::rc::Rc;
#[derive(Clone)]
pub struct TypeInstantiation {
type_name: TypeId,
generics: Vec<TypeId>,
fields: Vec<VarAssign>,
cached_type: Option<CheckedType>,
location: Option<SpanTuple>,
}
impl TypeInstantiation {
pub fn new(type_name: TypeId) -> TypeInstantiation {
TypeInstantiation {
type_name,
generics: vec![],
fields: vec![],
cached_type: None,
location: None,
}
}
pub fn add_field(&mut self, arg: VarAssign) {
self.fields.push(arg)
}
pub fn name(&self) -> &TypeId {
&self.type_name
}
pub fn fields(&self) -> &Vec<VarAssign> {
&self.fields
}
fn get_declaration(&self, ctx: &mut Context) -> Option<Rc<TypeDec>> {
match ctx.get_type(self.name()) {
Some(t) => Some(t.clone()),
None => {
ctx.error(
Error::new(ErrKind::Context)
.with_msg(format!("Cannot find type {}", self.name().id()))
.with_loc(self.location.clone()),
);
None
}
}
}
fn check_fields_count(&self, type_dec: &TypeDec) -> Result<(), Error> {
match self.fields().len() == type_dec.fields().len() {
true => Ok(()),
false => Err(Error::new(ErrKind::Context).with_msg(format!(
"Wrong number of arguments \
for type instantiation `{}`: Expected {}, got {}",
self.name().id(),
type_dec.fields().len(),
self.fields().len()
))),
}
}
pub fn set_generics(&mut self, generics: Vec<TypeId>) {
self.generics = generics
}
pub fn set_location(&mut self, location: SpanTuple) {
self.location = Some(location)
}
pub fn resolve_generic_instantiation(
&mut self,
dec: TypeDec,
ctx: &mut TypeCtx,
) -> CheckedType {
let type_map = match GenericMap::create(dec.generics(), &self.generics, ctx) {
Ok(map) => map,
Err(e) => {
ctx.error(e.with_loc(self.location.clone()));
return CheckedType::Error;
}
};
let specialized_name = generics::mangle(dec.name(), &self.generics);
if ctx.get_custom_type(&specialized_name).is_none() {
let specialized_ty = dec.generate(specialized_name.clone(), &type_map, ctx);
ctx.add_specialized_node(SpecializedNode::Type(specialized_ty));
}
self.type_name = TypeId::new(Symbol::from(specialized_name));
self.generics = vec![];
self.type_of(ctx)
}
}
impl Instruction for TypeInstantiation {
fn kind(&self) -> InstrKind {
InstrKind::Expression(None)
}
fn print(&self) -> String {
let mut base = format!("{}(", self.type_name.id());
let mut first_arg = true;
for arg in &self.fields {
if !first_arg {
base.push_str(", ");
}
base.push_str(&arg.print());
first_arg = false;
}
format!("{})", base)
}
fn execute(&self, ctx: &mut Context) -> Option<ObjectInstance> {
let type_dec = self.get_declaration(ctx)?;
if let Err(e) = self.check_fields_count(&type_dec) {
ctx.error(e);
return None;
}
let mut size: usize = 0;
let mut data: Vec<u8> = Vec::new();
let mut fields: Vec<(Name, ObjectInstance)> = Vec::new();
for (_, named_arg) in self.fields.iter().enumerate() {
let field_instr = named_arg.value();
let field_name = named_arg.symbol();
let instance = field_instr.execute_expression(ctx)?;
size += instance.size();
data.append(&mut instance.data().to_vec());
fields.push((field_name.to_string(), instance));
}
Some(ObjectInstance::new(
CheckedType::Resolved((*type_dec).clone().into()),
size,
data,
Some(fields),
))
}
}
impl TypeCheck for TypeInstantiation {
fn resolve_type(&mut self, ctx: &mut TypeCtx) -> CheckedType {
let dec = match ctx.get_custom_type(self.type_name.id()) {
Some(ty) => ty.clone(),
None => {
ctx.error(
Error::new(ErrKind::TypeChecker)
.with_msg(format!(
"use of undeclared type `{}`",
CheckedType::Resolved(self.type_name.clone())
))
.with_loc(self.location.clone()),
);
return CheckedType::Error;
}
};
if !dec.generics().is_empty() || !self.generics.is_empty() {
return self.resolve_generic_instantiation(dec, ctx);
}
let mut errors = vec![];
for (field_dec, var_assign) in dec.fields().iter().zip(self.fields.iter_mut()) {
let expected_ty = CheckedType::Resolved(field_dec.get_type().clone());
let value_ty = var_assign.value_mut().type_of(ctx);
if expected_ty != value_ty {
errors.push(
Error::new(ErrKind::TypeChecker)
.with_msg(format!(
"trying to assign value of type `{}` to field of type `{}`",
value_ty,
field_dec.get_type()
))
.with_loc(var_assign.location().cloned())
.with_hint(
Error::hint()
.with_msg(format!("field `{}` declared here", field_dec.name()))
.with_loc(field_dec.location().cloned()),
),
);
}
}
errors.into_iter().for_each(|err| ctx.error(err));
CheckedType::Resolved(self.type_name.clone())
}
fn set_cached_type(&mut self, ty: CheckedType) {
self.cached_type = Some(ty)
}
fn cached_type(&self) -> Option<&CheckedType> {
self.cached_type.as_ref()
}
}
impl GenericUser for TypeInstantiation {
fn resolve_usages(&mut self, type_map: &GenericMap, ctx: &mut TypeCtx) {
let dec = match ctx.get_custom_type(self.type_name.id()) {
Some(t) => t,
None => {
ctx.error(Error::new(ErrKind::Generics).with_msg(format!("trying to access undeclared type when resolving generic type instantiation: `{}`", self.type_name)).with_loc(self.location.clone()));
return;
}
};
let new_types = match type_map.specialized_types(dec.generics()) {
Err(e) => {
ctx.error(e.with_loc(self.location().cloned()));
return;
}
Ok(new_t) => new_t,
};
let new_name = generics::mangle(self.type_name.id(), &new_types);
let old_name = String::from(self.type_name.id());
self.type_name = TypeId::new(Symbol::from(new_name.clone()));
self.generics = vec![];
self.fields
.iter_mut()
.for_each(|arg| arg.resolve_usages(type_map, ctx));
if ctx.get_specialized_node(self.type_name.id()).is_none()
&& self.type_name.id() != old_name
{
let demangled = generics::demangle(self.type_name.id());
let generic_dec = ctx.get_custom_type(demangled).unwrap().clone();
let specialized_ty = generic_dec.generate(new_name, type_map, ctx);
ctx.add_specialized_node(SpecializedNode::Type(specialized_ty));
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{jinko_fail, symbol::Symbol};
#[test]
fn t_fields_number() {
use super::super::DecArg;
use crate::typechecker::TypeId;
use crate::value::JkInt;
let mut ctx = Context::new(Box::new(crate::io_trait::JkStdReader));
let fields = vec![
DecArg::new("a".to_owned(), TypeId::from("int")),
DecArg::new("b".to_owned(), TypeId::from("int")),
];
let t = TypeDec::new("Type_Test".to_owned(), vec![], fields);
t.execute(&mut ctx);
let mut t_inst = TypeInstantiation::new(TypeId::from("Type_Test"));
assert!(t_inst.execute(&mut ctx).is_none());
assert!(
ctx.error_handler.has_errors(),
"Given 0 field to 2 fields type"
);
ctx.clear_errors();
t_inst.add_field(VarAssign::new(
false,
"a".to_string(),
Box::new(JkInt::from(12)),
));
assert!(t_inst.execute(&mut ctx).is_none());
assert!(
ctx.error_handler.has_errors(),
"Given 1 field to 2 fields type"
);
ctx.clear_errors();
t_inst.add_field(VarAssign::new(
false,
"b".to_string(),
Box::new(JkInt::from(8)),
));
assert!(
t_inst.execute(&mut ctx).is_some(),
"Type instantiation should have a correct number of fields now"
);
assert!(!ctx.error_handler.has_errors());
}
#[test]
fn t_returned_instance() {
use super::super::DecArg;
use crate::typechecker::TypeId;
use crate::value::{JkInt, JkString};
const TYPE_NAME: &str = "Type_Name";
let mut ctx = Context::new(Box::new(crate::io_trait::JkStdReader));
let fields = vec![
DecArg::new("a".to_owned(), TypeId::from("string")),
DecArg::new("b".to_owned(), TypeId::from("int")),
];
let t = TypeDec::new(TYPE_NAME.to_owned(), vec![], fields);
t.execute(&mut ctx);
let mut t_inst = TypeInstantiation::new(TypeId::new(Symbol::from(TYPE_NAME.to_string())));
t_inst.add_field(VarAssign::new(
false,
"a".to_string(),
Box::new(JkString::from("I am a loooooooong string")),
));
t_inst.add_field(VarAssign::new(
false,
"b".to_string(),
Box::new(JkInt::from(12)),
));
let instance = match t_inst.execute(&mut ctx) {
Some(instance) => instance,
None => {
unreachable!("Type instantiation should have returned an Expression")
}
};
assert_eq!(
instance.data()[..],
[
73, 32, 97, 109, 32, 97, 32, 108, 111, 111, 111, 111, 111, 111, 111, 111, 110, 103,
32, 115, 116, 114, 105, 110, 103, 12, 0, 0, 0, 0, 0, 0, 0
]
);
assert_eq!(instance.size(), 33);
assert_eq!(
instance
.fields()
.as_ref()
.unwrap()
.get("a")
.unwrap()
.offset(),
&0usize
);
assert_eq!(
instance
.fields()
.as_ref()
.unwrap()
.get("b")
.unwrap()
.offset(),
&25usize
);
}
#[test]
fn t_instantiate_primitive() {
jinko_fail! {
i = int(no_fields: 15);
};
}
}