Nearly fix struct mutability
This commit is contained in:
parent
017b474f0c
commit
cd31d7e7cd
@ -310,10 +310,12 @@ impl Builder {
|
|||||||
Instr::ArrayAlloca(_, _) => Ok(()),
|
Instr::ArrayAlloca(_, _) => Ok(()),
|
||||||
Instr::GetElemPtr(ptr_val, _) => {
|
Instr::GetElemPtr(ptr_val, _) => {
|
||||||
let ptr_ty = ptr_val.get_type(&self)?;
|
let ptr_ty = ptr_val.get_type(&self)?;
|
||||||
if let Type::Ptr(_) = ptr_ty {
|
match ptr_ty {
|
||||||
Ok(())
|
Type::CustomType(custom) => match self.type_data(&custom).kind {
|
||||||
} else {
|
CustomTypeKind::NamedStruct(_) => Ok(()),
|
||||||
Err(()) // TODO error: not a pointer
|
},
|
||||||
|
Type::Ptr(_) => Ok(()),
|
||||||
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instr::GetStructElemPtr(ptr_val, idx) => {
|
Instr::GetStructElemPtr(ptr_val, idx) => {
|
||||||
|
@ -317,6 +317,8 @@ impl InstructionValue {
|
|||||||
GetElemPtr(ptr, _) => ptr.get_type(builder),
|
GetElemPtr(ptr, _) => ptr.get_type(builder),
|
||||||
GetStructElemPtr(instr, idx) => {
|
GetStructElemPtr(instr, idx) => {
|
||||||
let instr_ty = instr.get_type(builder)?;
|
let instr_ty = instr.get_type(builder)?;
|
||||||
|
dbg!(&builder);
|
||||||
|
dbg!(&instr, &instr_ty, idx);
|
||||||
let Type::Ptr(inner_ty) = instr_ty else {
|
let Type::Ptr(inner_ty) = instr_ty else {
|
||||||
panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty)
|
panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty)
|
||||||
};
|
};
|
||||||
|
@ -65,7 +65,7 @@ impl mir::Module {
|
|||||||
// TODO: Reorder custom-type definitions such that
|
// TODO: Reorder custom-type definitions such that
|
||||||
// inner types get evaluated first. Otherwise this
|
// inner types get evaluated first. Otherwise this
|
||||||
// will cause a panic!
|
// will cause a panic!
|
||||||
.map(|StructField(_, t, _)| t.get_type(&type_values))
|
.map(|StructField(_, t, _)| t.get_type(&type_values, &types))
|
||||||
.collect(),
|
.collect(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
@ -80,14 +80,14 @@ impl mir::Module {
|
|||||||
let param_types: Vec<Type> = function
|
let param_types: Vec<Type> = function
|
||||||
.parameters
|
.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, p)| p.get_type(&type_values))
|
.map(|(_, p)| p.get_type(&type_values, &types))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let is_main = self.is_main && function.name == "main";
|
let is_main = self.is_main && function.name == "main";
|
||||||
let func = match &function.kind {
|
let func = match &function.kind {
|
||||||
mir::FunctionDefinitionKind::Local(_, _) => module.function(
|
mir::FunctionDefinitionKind::Local(_, _) => module.function(
|
||||||
&function.name,
|
&function.name,
|
||||||
function.return_type.get_type(&type_values),
|
function.return_type.get_type(&type_values, &types),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
is_pub: function.is_pub || is_main,
|
is_pub: function.is_pub || is_main,
|
||||||
@ -98,7 +98,7 @@ impl mir::Module {
|
|||||||
),
|
),
|
||||||
mir::FunctionDefinitionKind::Extern(imported) => module.function(
|
mir::FunctionDefinitionKind::Extern(imported) => module.function(
|
||||||
&function.name,
|
&function.name,
|
||||||
function.return_type.get_type(&type_values),
|
function.return_type.get_type(&type_values, &types),
|
||||||
param_types,
|
param_types,
|
||||||
FunctionFlags {
|
FunctionFlags {
|
||||||
is_extern: true,
|
is_extern: true,
|
||||||
@ -120,7 +120,7 @@ impl mir::Module {
|
|||||||
p_name.clone(),
|
p_name.clone(),
|
||||||
StackValue(
|
StackValue(
|
||||||
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
|
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
|
||||||
p_ty.get_type(&type_values),
|
p_ty.get_type(&type_values, &types),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -202,48 +202,6 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexedVariableReference {
|
|
||||||
fn get_stack_value(&self, scope: &mut Scope) -> Option<(StackValue, Vec<u32>)> {
|
|
||||||
match &self.kind {
|
|
||||||
mir::IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => scope
|
|
||||||
.stack_values
|
|
||||||
.get(name)
|
|
||||||
.cloned()
|
|
||||||
.map(|v| (v, Vec::new())),
|
|
||||||
mir::IndexedVariableReferenceKind::ArrayIndex(inner, idx) => {
|
|
||||||
let (inner_val, mut indices) = inner.get_stack_value(scope)?;
|
|
||||||
|
|
||||||
match &inner_val.1 {
|
|
||||||
Type::Ptr(_) => {
|
|
||||||
indices.push(*idx as u32);
|
|
||||||
Some((inner_val, indices))
|
|
||||||
}
|
|
||||||
_ => panic!("Tried to codegen indexing a non-indexable value!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::IndexedVariableReferenceKind::StructIndex(inner, field) => {
|
|
||||||
let (inner_val, mut indices) = inner.get_stack_value(scope)?;
|
|
||||||
|
|
||||||
let idx = if let Type::CustomType(ty_val) = inner_val.1 {
|
|
||||||
match scope.types.get(&ty_val).unwrap() {
|
|
||||||
TypeDefinitionKind::Struct(struct_type) => struct_type.find_index(field),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}?;
|
|
||||||
|
|
||||||
match &inner_val.1 {
|
|
||||||
Type::Ptr(_) => {
|
|
||||||
indices.push(idx as u32);
|
|
||||||
Some((inner_val, indices))
|
|
||||||
}
|
|
||||||
_ => panic!("Tried to codegen indexing a non-indexable value!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::Statement {
|
impl mir::Statement {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
@ -255,13 +213,22 @@ impl mir::Statement {
|
|||||||
match mutable {
|
match mutable {
|
||||||
false => StackValueKind::Immutable(value),
|
false => StackValueKind::Immutable(value),
|
||||||
true => match ty {
|
true => match ty {
|
||||||
|
// Struct is already allocated at initialization
|
||||||
TypeKind::Array(_, _) => StackValueKind::Mutable(value),
|
TypeKind::Array(_, _) => StackValueKind::Mutable(value),
|
||||||
|
TypeKind::CustomType(n) => match scope
|
||||||
|
.types
|
||||||
|
.get(scope.type_values.get(n).unwrap())
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
// Struct also is allocated at initialization
|
||||||
|
TypeDefinitionKind::Struct(_) => StackValueKind::Mutable(value),
|
||||||
|
},
|
||||||
_ => StackValueKind::Mutable({
|
_ => StackValueKind::Mutable({
|
||||||
let alloca = scope
|
let alloca = scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Alloca(
|
.build(Instr::Alloca(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
ty.get_type(scope.type_values),
|
ty.get_type(scope.type_values, scope.types),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
scope.block.build(Instr::Store(alloca, value)).unwrap();
|
scope.block.build(Instr::Store(alloca, value)).unwrap();
|
||||||
@ -269,7 +236,7 @@ impl mir::Statement {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ty.get_type(scope.type_values),
|
ty.get_type(scope.type_values, scope.types),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
@ -454,7 +421,10 @@ impl mir::Expression {
|
|||||||
Some(
|
Some(
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Load(ptr, val_t.get_type(scope.type_values)))
|
.build(Instr::Load(
|
||||||
|
ptr,
|
||||||
|
val_t.get_type(scope.type_values, scope.types),
|
||||||
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -472,7 +442,7 @@ impl mir::Expression {
|
|||||||
let array = scope
|
let array = scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::ArrayAlloca(
|
.build(Instr::ArrayAlloca(
|
||||||
instr_t.get_type(scope.type_values),
|
instr_t.get_type(scope.type_values, scope.types),
|
||||||
instr_list.len() as u32,
|
instr_list.len() as u32,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -502,10 +472,14 @@ impl mir::Expression {
|
|||||||
.build(Instr::GetStructElemPtr(struct_val, idx as u32))
|
.build(Instr::GetStructElemPtr(struct_val, idx as u32))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
dbg!(&type_kind.get_type(scope.type_values, scope.types));
|
||||||
Some(
|
Some(
|
||||||
scope
|
scope
|
||||||
.block
|
.block
|
||||||
.build(Instr::Load(ptr, type_kind.get_type(scope.type_values)))
|
.build(Instr::Load(
|
||||||
|
ptr,
|
||||||
|
type_kind.get_type(scope.type_values, scope.types),
|
||||||
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -534,6 +508,56 @@ impl mir::Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IndexedVariableReference {
|
||||||
|
fn get_stack_value(&self, scope: &mut Scope) -> Option<(StackValue, Vec<u32>)> {
|
||||||
|
match &self.kind {
|
||||||
|
mir::IndexedVariableReferenceKind::Named(NamedVariableRef(_, name, _)) => scope
|
||||||
|
.stack_values
|
||||||
|
.get(name)
|
||||||
|
.cloned()
|
||||||
|
.map(|v| (v, Vec::new())),
|
||||||
|
mir::IndexedVariableReferenceKind::ArrayIndex(inner, idx) => {
|
||||||
|
let (inner_val, mut indices) = inner.get_stack_value(scope)?;
|
||||||
|
|
||||||
|
match &inner_val.1 {
|
||||||
|
Type::Ptr(_) => {
|
||||||
|
indices.push(*idx as u32);
|
||||||
|
Some((inner_val, indices))
|
||||||
|
}
|
||||||
|
_ => panic!("Tried to codegen indexing a non-indexable value!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mir::IndexedVariableReferenceKind::StructIndex(inner, field) => {
|
||||||
|
let (inner_val, mut indices) = inner.get_stack_value(scope)?;
|
||||||
|
|
||||||
|
let (idx, elem_ty) = if let Type::Ptr(inner_ty) = inner_val.1 {
|
||||||
|
if let Type::CustomType(ty_val) = *inner_ty {
|
||||||
|
match scope.types.get(&ty_val).unwrap() {
|
||||||
|
TypeDefinitionKind::Struct(struct_type) => Some((
|
||||||
|
struct_type.find_index(field)?,
|
||||||
|
struct_type.get_field_ty(field)?,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}?;
|
||||||
|
|
||||||
|
indices.push(idx as u32);
|
||||||
|
Some((
|
||||||
|
StackValue(
|
||||||
|
inner_val.0,
|
||||||
|
Type::Ptr(Box::new(elem_ty.get_type(scope.type_values, scope.types))),
|
||||||
|
),
|
||||||
|
indices,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl mir::CmpOperator {
|
impl mir::CmpOperator {
|
||||||
fn int_predicate(&self) -> CmpPredicate {
|
fn int_predicate(&self) -> CmpPredicate {
|
||||||
match self {
|
match self {
|
||||||
@ -596,7 +620,11 @@ impl mir::Literal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
fn get_type(&self, type_vals: &HashMap<String, TypeValue>) -> Type {
|
fn get_type(
|
||||||
|
&self,
|
||||||
|
type_vals: &HashMap<String, TypeValue>,
|
||||||
|
typedefs: &HashMap<TypeValue, TypeDefinitionKind>,
|
||||||
|
) -> Type {
|
||||||
match &self {
|
match &self {
|
||||||
TypeKind::I8 => Type::I8,
|
TypeKind::I8 => Type::I8,
|
||||||
TypeKind::I16 => Type::I16,
|
TypeKind::I16 => Type::I16,
|
||||||
@ -610,10 +638,16 @@ impl TypeKind {
|
|||||||
TypeKind::U128 => Type::U128,
|
TypeKind::U128 => Type::U128,
|
||||||
TypeKind::Bool => Type::Bool,
|
TypeKind::Bool => Type::Bool,
|
||||||
TypeKind::StringPtr => Type::Ptr(Box::new(Type::I8)),
|
TypeKind::StringPtr => Type::Ptr(Box::new(Type::I8)),
|
||||||
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type(type_vals))),
|
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type(type_vals, typedefs))),
|
||||||
TypeKind::Void => Type::Void,
|
TypeKind::Void => Type::Void,
|
||||||
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
||||||
TypeKind::CustomType(n) => Type::CustomType(type_vals.get(n).unwrap().clone()),
|
TypeKind::CustomType(n) => {
|
||||||
|
let type_val = type_vals.get(n).unwrap().clone();
|
||||||
|
let custom_t = Type::CustomType(type_val);
|
||||||
|
match typedefs.get(&type_val).unwrap() {
|
||||||
|
TypeDefinitionKind::Struct(_) => Type::Ptr(Box::new(custom_t)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ impl Display for TypeDefinitionKind {
|
|||||||
|
|
||||||
impl Display for StructField {
|
impl Display for StructField {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, "{}: {:?},", self.0, self.1)
|
write!(f, "{}: {:?}", self.0, self.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +33,6 @@ impl<TErr: STDError> STDError for Error<TErr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State<TErr: STDError> {
|
pub struct State<TErr: STDError> {
|
||||||
pub errors: Vec<Error<TErr>>,
|
pub errors: Vec<Error<TErr>>,
|
||||||
@ -84,6 +81,9 @@ impl<TErr: STDError> State<TErr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>);
|
||||||
|
|
||||||
impl<T: std::fmt::Debug> Default for Storage<T> {
|
impl<T: std::fmt::Debug> Default for Storage<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(Default::default())
|
Self(Default::default())
|
||||||
@ -114,6 +114,24 @@ pub struct Scope {
|
|||||||
pub return_type_hint: Option<TypeKind>,
|
pub return_type_hint: Option<TypeKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn inner(&self) -> Scope {
|
||||||
|
Scope {
|
||||||
|
function_returns: self.function_returns.clone(),
|
||||||
|
variables: self.variables.clone(),
|
||||||
|
types: self.types.clone(),
|
||||||
|
return_type_hint: self.return_type_hint.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_struct_type(&self, name: &String) -> Option<&StructType> {
|
||||||
|
let ty = self.types.get(&name)?;
|
||||||
|
match ty {
|
||||||
|
TypeDefinitionKind::Struct(struct_ty) => Some(struct_ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ScopeFunction {
|
pub struct ScopeFunction {
|
||||||
pub ret: TypeKind,
|
pub ret: TypeKind,
|
||||||
@ -126,17 +144,6 @@ pub struct ScopeVariable {
|
|||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
|
||||||
pub fn inner(&self) -> Scope {
|
|
||||||
Scope {
|
|
||||||
function_returns: self.function_returns.clone(),
|
|
||||||
variables: self.variables.clone(),
|
|
||||||
types: self.types.clone(),
|
|
||||||
return_type_hint: self.return_type_hint.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
|
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
|
||||||
state: &'st mut State<TError>,
|
state: &'st mut State<TError>,
|
||||||
pub scope: &'sc mut Scope,
|
pub scope: &'sc mut Scope,
|
||||||
|
@ -186,7 +186,7 @@ impl Block {
|
|||||||
fn typecheck(
|
fn typecheck(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PassState<ErrorKind>,
|
state: &mut PassState<ErrorKind>,
|
||||||
hints: &TypeRefs,
|
typerefs: &TypeRefs,
|
||||||
hint_t: Option<&TypeKind>,
|
hint_t: Option<&TypeKind>,
|
||||||
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
|
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
|
||||||
let mut state = state.inner();
|
let mut state = state.inner();
|
||||||
@ -197,10 +197,10 @@ impl Block {
|
|||||||
let ret = match &mut statement.0 {
|
let ret = match &mut statement.0 {
|
||||||
StmtKind::Let(variable_reference, mutable, expression) => {
|
StmtKind::Let(variable_reference, mutable, expression) => {
|
||||||
// Resolve possible hint in var reference
|
// Resolve possible hint in var reference
|
||||||
let var_t_resolved = variable_reference.0.resolve_hinted(&hints);
|
let var_t_resolved = variable_reference.0.resolve_ref(&typerefs);
|
||||||
|
|
||||||
// Typecheck (and coerce) expression with said type
|
// Typecheck (and coerce) expression with said type
|
||||||
let res = expression.typecheck(&mut state, &hints, Some(&var_t_resolved));
|
let res = expression.typecheck(&mut state, &typerefs, Some(&var_t_resolved));
|
||||||
|
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
// Unknown and note error.
|
// Unknown and note error.
|
||||||
@ -222,7 +222,7 @@ impl Block {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Re-typecheck and coerce expression to default type
|
// Re-typecheck and coerce expression to default type
|
||||||
let expr_res = expression.typecheck(&mut state, &hints, Some(&res_t));
|
let expr_res = expression.typecheck(&mut state, &typerefs, Some(&res_t));
|
||||||
state.ok(expr_res, expression.1);
|
state.ok(expr_res, expression.1);
|
||||||
|
|
||||||
res_t
|
res_t
|
||||||
@ -251,6 +251,9 @@ impl Block {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
StmtKind::Set(variable_reference, expression) => {
|
StmtKind::Set(variable_reference, expression) => {
|
||||||
|
// Update typing from reference
|
||||||
|
variable_reference.resolve_ref(&typerefs)?;
|
||||||
|
|
||||||
if let Some(var) = state
|
if let Some(var) = state
|
||||||
.ok(
|
.ok(
|
||||||
variable_reference
|
variable_reference
|
||||||
@ -259,8 +262,11 @@ impl Block {
|
|||||||
)
|
)
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
|
let field_ty = variable_reference.retrieve_type(&state.scope)?;
|
||||||
|
dbg!(&field_ty);
|
||||||
|
|
||||||
// Typecheck expression and coerce to variable type
|
// Typecheck expression and coerce to variable type
|
||||||
let res = expression.typecheck(&mut state, &hints, Some(&var.ty));
|
let res = expression.typecheck(&mut state, &typerefs, Some(&field_ty));
|
||||||
|
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
// Unknown.
|
// Unknown.
|
||||||
@ -269,15 +275,11 @@ impl Block {
|
|||||||
|
|
||||||
// Make sure the expression and variable type to really
|
// Make sure the expression and variable type to really
|
||||||
// be the same
|
// be the same
|
||||||
let res_t = state.or_else(
|
state.ok(
|
||||||
expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)),
|
expr_ty.collapse_into(&field_ty),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
|
||||||
variable_reference.meta + expression.1,
|
variable_reference.meta + expression.1,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update typing to be more accurate
|
|
||||||
variable_reference.update_type(&res_t);
|
|
||||||
|
|
||||||
if !var.mutable {
|
if !var.mutable {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::VariableNotMutable(variable_reference.get_name())),
|
Err(ErrorKind::VariableNotMutable(variable_reference.get_name())),
|
||||||
@ -296,7 +298,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
StmtKind::Import(_) => todo!(), // TODO
|
StmtKind::Import(_) => todo!(), // TODO
|
||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
let res = expression.typecheck(&mut state, &hints, None);
|
let res = expression.typecheck(&mut state, &typerefs, None);
|
||||||
state.or_else(res, TypeKind::Void, expression.1);
|
state.or_else(res, TypeKind::Void, expression.1);
|
||||||
if let Ok((kind, _)) = expression.return_type() {
|
if let Ok((kind, _)) = expression.return_type() {
|
||||||
Some((kind, expression))
|
Some((kind, expression))
|
||||||
@ -316,7 +318,7 @@ impl Block {
|
|||||||
// block)
|
// block)
|
||||||
if let Some((ReturnKind::Hard, expr)) = early_return {
|
if let Some((ReturnKind::Hard, expr)) = early_return {
|
||||||
let hint = state.scope.return_type_hint.clone();
|
let hint = state.scope.return_type_hint.clone();
|
||||||
let res = expr.typecheck(&mut state, &hints, hint.as_ref());
|
let res = expr.typecheck(&mut state, &typerefs, hint.as_ref());
|
||||||
return Ok((
|
return Ok((
|
||||||
ReturnKind::Hard,
|
ReturnKind::Hard,
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
||||||
@ -329,7 +331,7 @@ impl Block {
|
|||||||
ReturnKind::Hard => state.scope.return_type_hint.clone(),
|
ReturnKind::Hard => state.scope.return_type_hint.clone(),
|
||||||
ReturnKind::Soft => hint_t.cloned(),
|
ReturnKind::Soft => hint_t.cloned(),
|
||||||
};
|
};
|
||||||
let res = expr.typecheck(&mut state, &hints, ret_hint_t.as_ref());
|
let res = expr.typecheck(&mut state, &typerefs, ret_hint_t.as_ref());
|
||||||
Ok((
|
Ok((
|
||||||
*return_kind,
|
*return_kind,
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
||||||
@ -361,11 +363,11 @@ impl Expression {
|
|||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
)
|
)
|
||||||
.resolve_hinted(hints);
|
.resolve_ref(hints);
|
||||||
|
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
var_ref.0 = state.or_else(
|
var_ref.0 = state.or_else(
|
||||||
var_ref.0.resolve_hinted(hints).collapse_into(&existing),
|
var_ref.0.resolve_ref(hints).collapse_into(&existing),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
);
|
);
|
||||||
@ -437,12 +439,12 @@ impl Expression {
|
|||||||
// return type
|
// return type
|
||||||
let ret_t = f
|
let ret_t = f
|
||||||
.ret
|
.ret
|
||||||
.collapse_into(&function_call.return_type.resolve_hinted(hints))?;
|
.collapse_into(&function_call.return_type.resolve_ref(hints))?;
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
function_call.return_type = ret_t.clone();
|
function_call.return_type = ret_t.clone();
|
||||||
Ok(ret_t.resolve_hinted(hints))
|
Ok(ret_t.resolve_ref(hints))
|
||||||
} else {
|
} else {
|
||||||
Ok(function_call.return_type.clone().resolve_hinted(hints))
|
Ok(function_call.return_type.clone().resolve_ref(hints))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||||
@ -515,7 +517,7 @@ impl Expression {
|
|||||||
return Err(ErrorKind::IndexOutOfBounds(*idx, len));
|
return Err(ErrorKind::IndexOutOfBounds(*idx, len));
|
||||||
}
|
}
|
||||||
let ty = state.or_else(
|
let ty = state.or_else(
|
||||||
elem_ty.resolve_hinted(hints).collapse_into(&inferred_ty),
|
elem_ty.resolve_ref(hints).collapse_into(&inferred_ty),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Vague::Unknown),
|
||||||
self.1,
|
self.1,
|
||||||
);
|
);
|
||||||
@ -564,7 +566,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
ExprKind::StructIndex(expression, type_kind, field_name) => {
|
ExprKind::StructIndex(expression, type_kind, field_name) => {
|
||||||
// Resolve expected type
|
// Resolve expected type
|
||||||
let expected_ty = type_kind.resolve_hinted(hints);
|
let expected_ty = type_kind.resolve_ref(hints);
|
||||||
|
|
||||||
// Typecheck expression
|
// Typecheck expression
|
||||||
let expr_res = expression.typecheck(state, hints, Some(&expected_ty));
|
let expr_res = expression.typecheck(state, hints, Some(&expected_ty));
|
||||||
@ -572,7 +574,10 @@ impl Expression {
|
|||||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
||||||
|
|
||||||
if let TypeKind::CustomType(struct_name) = expr_ty {
|
if let TypeKind::CustomType(struct_name) = expr_ty {
|
||||||
let struct_type = state.scope.get_struct_type(&struct_name)?;
|
let struct_type = state
|
||||||
|
.scope
|
||||||
|
.get_struct_type(&struct_name)
|
||||||
|
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?;
|
||||||
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
|
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
|
||||||
// Make sure they are the same
|
// Make sure they are the same
|
||||||
let true_ty = state.or_else(
|
let true_ty = state.or_else(
|
||||||
@ -591,7 +596,11 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Struct(struct_name, items) => {
|
ExprKind::Struct(struct_name, items) => {
|
||||||
let struct_def = state.scope.get_struct_type(struct_name)?.clone();
|
let struct_def = state
|
||||||
|
.scope
|
||||||
|
.get_struct_type(struct_name)
|
||||||
|
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
|
||||||
|
.clone();
|
||||||
for (field_name, field_expr) in items {
|
for (field_name, field_expr) in items {
|
||||||
// Get expected type, or error if field does not exist
|
// Get expected type, or error if field does not exist
|
||||||
let expected_ty = state.or_else(
|
let expected_ty = state.or_else(
|
||||||
@ -718,37 +727,7 @@ impl Literal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {}
|
||||||
/// Assert that a type is already known and not vague. Return said type or
|
|
||||||
/// error.
|
|
||||||
pub fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
|
|
||||||
self.known().map_err(ErrorKind::TypeIsVague)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to collapse a type on itself producing a default type if one exists,
|
|
||||||
/// Error if not.
|
|
||||||
fn or_default(&self) -> Result<TypeKind, ErrorKind> {
|
|
||||||
match self {
|
|
||||||
TypeKind::Vague(vague_type) => match &vague_type {
|
|
||||||
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
|
|
||||||
Vague::Number => Ok(TypeKind::I32),
|
|
||||||
Vague::TypeRef(_) => panic!("Hinted default!"),
|
|
||||||
},
|
|
||||||
_ => Ok(self.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind {
|
|
||||||
let resolved = match self {
|
|
||||||
TypeKind::Vague(Vague::TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
|
|
||||||
_ => self.clone(),
|
|
||||||
};
|
|
||||||
match resolved {
|
|
||||||
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_hinted(hints)), len),
|
|
||||||
_ => resolved,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Collapsable: Sized + Clone {
|
pub trait Collapsable: Sized + Clone {
|
||||||
/// Try to narrow two types into one singular type. E.g. Vague(Number) and
|
/// Try to narrow two types into one singular type. E.g. Vague(Number) and
|
||||||
@ -803,15 +782,3 @@ impl Collapsable for ScopeFunction {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pass::Scope {
|
|
||||||
pub fn get_struct_type(&self, name: &String) -> Result<&StructType, ErrorKind> {
|
|
||||||
let ty = self
|
|
||||||
.types
|
|
||||||
.get(&name)
|
|
||||||
.ok_or(ErrorKind::NoSuchType(name.clone()))?;
|
|
||||||
match ty {
|
|
||||||
TypeDefinitionKind::Struct(struct_ty) => Ok(struct_ty),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -106,13 +106,8 @@ impl Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Set(var, expr) => {
|
StmtKind::Set(var, expr) => {
|
||||||
// Get the TypeRef for this variable declaration
|
// Update this MIR type to its TypeRef
|
||||||
let var_ref = var.find_hint(&state, &inner_hints)?;
|
let var_ref = var.into_typeref(&inner_hints);
|
||||||
|
|
||||||
// If ok, update the MIR type to this TypeRef
|
|
||||||
if let Some((_, var_ref)) = &var_ref {
|
|
||||||
var.update_type(&var_ref.as_type());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infer hints for the expression itself
|
// Infer hints for the expression itself
|
||||||
let inferred = expr.infer_types(&mut state, &inner_hints);
|
let inferred = expr.infer_types(&mut state, &inner_hints);
|
||||||
@ -371,7 +366,10 @@ impl Expression {
|
|||||||
let kind = expr_ty.resolve_weak().unwrap();
|
let kind = expr_ty.resolve_weak().unwrap();
|
||||||
match kind {
|
match kind {
|
||||||
CustomType(name) => {
|
CustomType(name) => {
|
||||||
let struct_ty = state.scope.get_struct_type(&name)?;
|
let struct_ty = state
|
||||||
|
.scope
|
||||||
|
.get_struct_type(&name)
|
||||||
|
.ok_or(ErrorKind::NoSuchType(name.clone()))?;
|
||||||
match struct_ty.get_field_ty(&field_name) {
|
match struct_ty.get_field_ty(&field_name) {
|
||||||
Some(field_ty) => {
|
Some(field_ty) => {
|
||||||
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
|
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
|
||||||
@ -386,7 +384,11 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::Struct(struct_name, fields) => {
|
ExprKind::Struct(struct_name, fields) => {
|
||||||
let expected_struct_ty = state.scope.get_struct_type(&struct_name)?.clone();
|
let expected_struct_ty = state
|
||||||
|
.scope
|
||||||
|
.get_struct_type(&struct_name)
|
||||||
|
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
|
||||||
|
.clone();
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
||||||
let field_ty = field.1.infer_types(state, type_refs);
|
let field_ty = field.1.infer_types(state, type_refs);
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
use super::*;
|
use super::{
|
||||||
|
typecheck::{Collapsable, ErrorKind},
|
||||||
|
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
||||||
|
VagueType as Vague, *,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ReturnTypeOther {
|
pub enum ReturnTypeOther {
|
||||||
@ -179,6 +183,38 @@ pub fn pick_return<T>(lhs: (ReturnKind, T), rhs: (ReturnKind, T)) -> (ReturnKind
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TypeKind {
|
||||||
|
/// Assert that a type is already known and not vague. Return said type or
|
||||||
|
/// error.
|
||||||
|
pub fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
|
||||||
|
self.known().map_err(ErrorKind::TypeIsVague)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to collapse a type on itself producing a default type if one exists,
|
||||||
|
/// Error if not.
|
||||||
|
pub fn or_default(&self) -> Result<TypeKind, ErrorKind> {
|
||||||
|
match self {
|
||||||
|
TypeKind::Vague(vague_type) => match &vague_type {
|
||||||
|
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
|
||||||
|
Vague::Number => Ok(TypeKind::I32),
|
||||||
|
Vague::TypeRef(_) => panic!("Hinted default!"),
|
||||||
|
},
|
||||||
|
_ => Ok(self.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_ref(&self, refs: &TypeRefs) -> TypeKind {
|
||||||
|
let resolved = match self {
|
||||||
|
TypeKind::Vague(Vague::TypeRef(idx)) => refs.retrieve_type(*idx).unwrap(),
|
||||||
|
_ => self.clone(),
|
||||||
|
};
|
||||||
|
match resolved {
|
||||||
|
TypeKind::Array(t, len) => TypeKind::Array(Box::new(t.resolve_ref(refs)), len),
|
||||||
|
_ => resolved,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IndexedVariableReference {
|
impl IndexedVariableReference {
|
||||||
pub fn get_name(&self) -> String {
|
pub fn get_name(&self) -> String {
|
||||||
match &self.kind {
|
match &self.kind {
|
||||||
@ -192,13 +228,55 @@ impl IndexedVariableReference {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_type(&mut self, new_ty: &TypeKind) {
|
/// Retrieve the indexed type that this variable reference is pointing to
|
||||||
|
pub fn retrieve_type(&self, scope: &pass::Scope) -> Result<TypeKind, ErrorKind> {
|
||||||
|
match &self.kind {
|
||||||
|
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => Ok(ty.clone()),
|
||||||
|
IndexedVariableReferenceKind::ArrayIndex(inner, _) => {
|
||||||
|
let inner_ty = inner.retrieve_type(scope)?;
|
||||||
|
match inner_ty {
|
||||||
|
TypeKind::Array(type_kind, _) => Ok(*type_kind),
|
||||||
|
_ => Err(ErrorKind::TriedIndexingNonArray(inner_ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IndexedVariableReferenceKind::StructIndex(inner, field_name) => {
|
||||||
|
let inner_ty = inner.retrieve_type(scope)?;
|
||||||
|
match inner_ty {
|
||||||
|
TypeKind::CustomType(struct_name) => {
|
||||||
|
let struct_ty = scope
|
||||||
|
.get_struct_type(&struct_name)
|
||||||
|
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?;
|
||||||
|
struct_ty
|
||||||
|
.get_field_ty(&field_name)
|
||||||
|
.ok_or(ErrorKind::NoSuchField(field_name.clone()))
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
_ => Err(ErrorKind::TriedAccessingNonStruct(inner_ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_typeref<'s>(&mut self, typerefs: &'s ScopeTypeRefs) -> Option<(bool, TypeRef<'s>)> {
|
||||||
|
match &mut self.kind {
|
||||||
|
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, name, _)) => {
|
||||||
|
let t = typerefs.find_var(name)?;
|
||||||
|
*ty = t.1.as_type();
|
||||||
|
Some(t)
|
||||||
|
}
|
||||||
|
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.into_typeref(typerefs),
|
||||||
|
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.into_typeref(typerefs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_ref<'s>(&mut self, typerefs: &'s TypeRefs) -> Result<TypeKind, ErrorKind> {
|
||||||
match &mut self.kind {
|
match &mut self.kind {
|
||||||
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => {
|
IndexedVariableReferenceKind::Named(NamedVariableRef(ty, _, _)) => {
|
||||||
*ty = new_ty.clone();
|
*ty = ty.resolve_ref(typerefs);
|
||||||
|
Ok(ty.clone())
|
||||||
}
|
}
|
||||||
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.update_type(new_ty),
|
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.resolve_ref(typerefs),
|
||||||
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.update_type(new_ty),
|
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.resolve_ref(typerefs),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,12 @@ struct Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> u32 {
|
fn main() -> u32 {
|
||||||
let value = Test {
|
let mut value = Test {
|
||||||
field: 5,
|
field: 5,
|
||||||
second: 3,
|
second: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
value.second = 17;
|
||||||
|
|
||||||
return value.second;
|
return value.second;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user