Nearly fix struct mutability

This commit is contained in:
Sofia 2025-07-16 20:27:01 +03:00
parent 017b474f0c
commit cd31d7e7cd
9 changed files with 249 additions and 155 deletions

View File

@ -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) => {

View File

@ -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)
};

View File

@ -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)),
}
}
}
}
}

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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),
}
}
}

View File

@ -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);

View File

@ -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),
}
}
}

View File

@ -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;
}