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