Nearly fix struct mutability
This commit is contained in:
parent
017b474f0c
commit
cd31d7e7cd
@ -310,10 +310,12 @@ impl Builder {
|
||||
Instr::ArrayAlloca(_, _) => Ok(()),
|
||||
Instr::GetElemPtr(ptr_val, _) => {
|
||||
let ptr_ty = ptr_val.get_type(&self)?;
|
||||
if let Type::Ptr(_) = ptr_ty {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(()) // TODO error: not a pointer
|
||||
match ptr_ty {
|
||||
Type::CustomType(custom) => match self.type_data(&custom).kind {
|
||||
CustomTypeKind::NamedStruct(_) => Ok(()),
|
||||
},
|
||||
Type::Ptr(_) => Ok(()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
Instr::GetStructElemPtr(ptr_val, idx) => {
|
||||
|
@ -317,6 +317,8 @@ impl InstructionValue {
|
||||
GetElemPtr(ptr, _) => ptr.get_type(builder),
|
||||
GetStructElemPtr(instr, idx) => {
|
||||
let instr_ty = instr.get_type(builder)?;
|
||||
dbg!(&builder);
|
||||
dbg!(&instr, &instr_ty, idx);
|
||||
let Type::Ptr(inner_ty) = instr_ty else {
|
||||
panic!("GetStructElemPtr on non-pointer! ({:?})", &instr_ty)
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ impl mir::Module {
|
||||
// TODO: Reorder custom-type definitions such that
|
||||
// inner types get evaluated first. Otherwise this
|
||||
// will cause a panic!
|
||||
.map(|StructField(_, t, _)| t.get_type(&type_values))
|
||||
.map(|StructField(_, t, _)| t.get_type(&type_values, &types))
|
||||
.collect(),
|
||||
)))
|
||||
}
|
||||
@ -80,14 +80,14 @@ impl mir::Module {
|
||||
let param_types: Vec<Type> = function
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|(_, p)| p.get_type(&type_values))
|
||||
.map(|(_, p)| p.get_type(&type_values, &types))
|
||||
.collect();
|
||||
|
||||
let is_main = self.is_main && function.name == "main";
|
||||
let func = match &function.kind {
|
||||
mir::FunctionDefinitionKind::Local(_, _) => module.function(
|
||||
&function.name,
|
||||
function.return_type.get_type(&type_values),
|
||||
function.return_type.get_type(&type_values, &types),
|
||||
param_types,
|
||||
FunctionFlags {
|
||||
is_pub: function.is_pub || is_main,
|
||||
@ -98,7 +98,7 @@ impl mir::Module {
|
||||
),
|
||||
mir::FunctionDefinitionKind::Extern(imported) => module.function(
|
||||
&function.name,
|
||||
function.return_type.get_type(&type_values),
|
||||
function.return_type.get_type(&type_values, &types),
|
||||
param_types,
|
||||
FunctionFlags {
|
||||
is_extern: true,
|
||||
@ -120,7 +120,7 @@ impl mir::Module {
|
||||
p_name.clone(),
|
||||
StackValue(
|
||||
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 {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
||||
match &self.0 {
|
||||
@ -255,13 +213,22 @@ impl mir::Statement {
|
||||
match mutable {
|
||||
false => StackValueKind::Immutable(value),
|
||||
true => match ty {
|
||||
// Struct is already allocated at initialization
|
||||
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({
|
||||
let alloca = scope
|
||||
.block
|
||||
.build(Instr::Alloca(
|
||||
name.clone(),
|
||||
ty.get_type(scope.type_values),
|
||||
ty.get_type(scope.type_values, scope.types),
|
||||
))
|
||||
.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
|
||||
@ -454,7 +421,10 @@ impl mir::Expression {
|
||||
Some(
|
||||
scope
|
||||
.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(),
|
||||
)
|
||||
}
|
||||
@ -472,7 +442,7 @@ impl mir::Expression {
|
||||
let array = scope
|
||||
.block
|
||||
.build(Instr::ArrayAlloca(
|
||||
instr_t.get_type(scope.type_values),
|
||||
instr_t.get_type(scope.type_values, scope.types),
|
||||
instr_list.len() as u32,
|
||||
))
|
||||
.unwrap();
|
||||
@ -502,10 +472,14 @@ impl mir::Expression {
|
||||
.build(Instr::GetStructElemPtr(struct_val, idx as u32))
|
||||
.unwrap();
|
||||
|
||||
dbg!(&type_kind.get_type(scope.type_values, scope.types));
|
||||
Some(
|
||||
scope
|
||||
.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(),
|
||||
)
|
||||
}
|
||||
@ -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 {
|
||||
fn int_predicate(&self) -> CmpPredicate {
|
||||
match self {
|
||||
@ -596,7 +620,11 @@ impl mir::Literal {
|
||||
}
|
||||
|
||||
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 {
|
||||
TypeKind::I8 => Type::I8,
|
||||
TypeKind::I16 => Type::I16,
|
||||
@ -610,10 +638,16 @@ impl TypeKind {
|
||||
TypeKind::U128 => Type::U128,
|
||||
TypeKind::Bool => Type::Bool,
|
||||
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::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 {
|
||||
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)]
|
||||
pub struct State<TErr: STDError> {
|
||||
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> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
@ -114,6 +114,24 @@ pub struct Scope {
|
||||
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)]
|
||||
pub struct ScopeFunction {
|
||||
pub ret: TypeKind,
|
||||
@ -126,17 +144,6 @@ pub struct ScopeVariable {
|
||||
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> {
|
||||
state: &'st mut State<TError>,
|
||||
pub scope: &'sc mut Scope,
|
||||
|
@ -186,7 +186,7 @@ impl Block {
|
||||
fn typecheck(
|
||||
&mut self,
|
||||
state: &mut PassState<ErrorKind>,
|
||||
hints: &TypeRefs,
|
||||
typerefs: &TypeRefs,
|
||||
hint_t: Option<&TypeKind>,
|
||||
) -> Result<(ReturnKind, TypeKind), ErrorKind> {
|
||||
let mut state = state.inner();
|
||||
@ -197,10 +197,10 @@ impl Block {
|
||||
let ret = match &mut statement.0 {
|
||||
StmtKind::Let(variable_reference, mutable, expression) => {
|
||||
// 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
|
||||
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
|
||||
// Unknown and note error.
|
||||
@ -222,7 +222,7 @@ impl Block {
|
||||
);
|
||||
|
||||
// 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);
|
||||
|
||||
res_t
|
||||
@ -251,6 +251,9 @@ impl Block {
|
||||
None
|
||||
}
|
||||
StmtKind::Set(variable_reference, expression) => {
|
||||
// Update typing from reference
|
||||
variable_reference.resolve_ref(&typerefs)?;
|
||||
|
||||
if let Some(var) = state
|
||||
.ok(
|
||||
variable_reference
|
||||
@ -259,8 +262,11 @@ impl Block {
|
||||
)
|
||||
.flatten()
|
||||
{
|
||||
let field_ty = variable_reference.retrieve_type(&state.scope)?;
|
||||
dbg!(&field_ty);
|
||||
|
||||
// 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
|
||||
// Unknown.
|
||||
@ -269,15 +275,11 @@ impl Block {
|
||||
|
||||
// Make sure the expression and variable type to really
|
||||
// be the same
|
||||
let res_t = state.or_else(
|
||||
expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)),
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
state.ok(
|
||||
expr_ty.collapse_into(&field_ty),
|
||||
variable_reference.meta + expression.1,
|
||||
);
|
||||
|
||||
// Update typing to be more accurate
|
||||
variable_reference.update_type(&res_t);
|
||||
|
||||
if !var.mutable {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::VariableNotMutable(variable_reference.get_name())),
|
||||
@ -296,7 +298,7 @@ impl Block {
|
||||
}
|
||||
StmtKind::Import(_) => todo!(), // TODO
|
||||
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);
|
||||
if let Ok((kind, _)) = expression.return_type() {
|
||||
Some((kind, expression))
|
||||
@ -316,7 +318,7 @@ impl Block {
|
||||
// block)
|
||||
if let Some((ReturnKind::Hard, expr)) = early_return {
|
||||
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((
|
||||
ReturnKind::Hard,
|
||||
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::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((
|
||||
*return_kind,
|
||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
||||
@ -361,11 +363,11 @@ impl Expression {
|
||||
TypeKind::Vague(Vague::Unknown),
|
||||
var_ref.2,
|
||||
)
|
||||
.resolve_hinted(hints);
|
||||
.resolve_ref(hints);
|
||||
|
||||
// Update typing to be more accurate
|
||||
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),
|
||||
var_ref.2,
|
||||
);
|
||||
@ -437,12 +439,12 @@ impl Expression {
|
||||
// return type
|
||||
let ret_t = f
|
||||
.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
|
||||
function_call.return_type = ret_t.clone();
|
||||
Ok(ret_t.resolve_hinted(hints))
|
||||
Ok(ret_t.resolve_ref(hints))
|
||||
} 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)) => {
|
||||
@ -515,7 +517,7 @@ impl Expression {
|
||||
return Err(ErrorKind::IndexOutOfBounds(*idx, len));
|
||||
}
|
||||
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),
|
||||
self.1,
|
||||
);
|
||||
@ -564,7 +566,7 @@ impl Expression {
|
||||
}
|
||||
ExprKind::StructIndex(expression, type_kind, field_name) => {
|
||||
// Resolve expected type
|
||||
let expected_ty = type_kind.resolve_hinted(hints);
|
||||
let expected_ty = type_kind.resolve_ref(hints);
|
||||
|
||||
// Typecheck expression
|
||||
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);
|
||||
|
||||
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) {
|
||||
// Make sure they are the same
|
||||
let true_ty = state.or_else(
|
||||
@ -591,7 +596,11 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
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 {
|
||||
// Get expected type, or error if field does not exist
|
||||
let expected_ty = state.or_else(
|
||||
@ -718,37 +727,7 @@ impl Literal {
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl TypeKind {}
|
||||
|
||||
pub trait Collapsable: Sized + Clone {
|
||||
/// 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) => {
|
||||
// Get the TypeRef for this variable declaration
|
||||
let var_ref = var.find_hint(&state, &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());
|
||||
}
|
||||
// Update this MIR type to its TypeRef
|
||||
let var_ref = var.into_typeref(&inner_hints);
|
||||
|
||||
// Infer hints for the expression itself
|
||||
let inferred = expr.infer_types(&mut state, &inner_hints);
|
||||
@ -371,7 +366,10 @@ impl Expression {
|
||||
let kind = expr_ty.resolve_weak().unwrap();
|
||||
match kind {
|
||||
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) {
|
||||
Some(field_ty) => {
|
||||
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
|
||||
@ -386,7 +384,11 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
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 {
|
||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
||||
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)]
|
||||
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 {
|
||||
pub fn get_name(&self) -> String {
|
||||
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 {
|
||||
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::StructIndex(inner, _) => inner.update_type(new_ty),
|
||||
IndexedVariableReferenceKind::ArrayIndex(inner, _) => inner.resolve_ref(typerefs),
|
||||
IndexedVariableReferenceKind::StructIndex(inner, _) => inner.resolve_ref(typerefs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,12 @@ struct Test {
|
||||
}
|
||||
|
||||
fn main() -> u32 {
|
||||
let value = Test {
|
||||
let mut value = Test {
|
||||
field: 5,
|
||||
second: 3,
|
||||
};
|
||||
|
||||
value.second = 17;
|
||||
|
||||
return value.second;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user