Implement mutability part 2
This commit is contained in:
parent
14e0dcbe15
commit
0f424c70d7
@ -4,7 +4,7 @@ fn indirection() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn main() -> u16 {
|
||||
fn main() -> i32 {
|
||||
let mut test = 5;
|
||||
|
||||
if indirection() {
|
||||
|
@ -163,8 +163,15 @@ impl mir::Statement {
|
||||
name.clone(),
|
||||
StackValue(
|
||||
match mutable {
|
||||
true => StackValueKind::Mutable(value),
|
||||
false => StackValueKind::Immutable(value),
|
||||
true => StackValueKind::Mutable({
|
||||
let alloca = scope
|
||||
.block
|
||||
.build(Instr::Alloca(name.clone(), ty.get_type()))
|
||||
.unwrap();
|
||||
scope.block.build(Instr::Store(alloca, value)).unwrap();
|
||||
alloca
|
||||
}),
|
||||
},
|
||||
ty.get_type(),
|
||||
),
|
||||
@ -172,13 +179,15 @@ impl mir::Statement {
|
||||
None
|
||||
}
|
||||
mir::StmtKind::Set(var, val) => {
|
||||
if let Some(StackValue(kind, ty)) = scope.stack_values.get(&var.1).cloned() {
|
||||
if let Some(StackValue(kind, _)) = scope.stack_values.get(&var.1).cloned() {
|
||||
match kind {
|
||||
StackValueKind::Immutable(ptr) => {
|
||||
StackValueKind::Immutable(_) => {
|
||||
panic!("Tried to mutate an immutable variable")
|
||||
}
|
||||
StackValueKind::Mutable(ptr) => {
|
||||
let expression = val.codegen(scope).unwrap();
|
||||
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
|
||||
}
|
||||
StackValueKind::Mutable(_) => panic!(""),
|
||||
}
|
||||
} else {
|
||||
panic!("")
|
||||
@ -251,7 +260,7 @@ impl mir::Expression {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
||||
match &self.0 {
|
||||
mir::ExprKind::Variable(varref) => {
|
||||
varref.0.is_known().expect("variable type unknown");
|
||||
varref.0.known().expect("variable type unknown");
|
||||
let v = scope
|
||||
.stack_values
|
||||
.get(&varref.1)
|
||||
@ -269,13 +278,13 @@ impl mir::Expression {
|
||||
.return_type()
|
||||
.expect("No ret type in lhs?")
|
||||
.1
|
||||
.is_known()
|
||||
.known()
|
||||
.expect("lhs ret type is unknown");
|
||||
rhs_exp
|
||||
.return_type()
|
||||
.expect("No ret type in rhs?")
|
||||
.1
|
||||
.is_known()
|
||||
.known()
|
||||
.expect("rhs ret type is unknown");
|
||||
|
||||
let lhs = lhs_exp.codegen(scope).expect("lhs has no return value");
|
||||
@ -293,7 +302,7 @@ impl mir::Expression {
|
||||
}
|
||||
mir::ExprKind::FunctionCall(call) => {
|
||||
call.return_type
|
||||
.is_known()
|
||||
.known()
|
||||
.expect("function return type unknown");
|
||||
|
||||
let params = call
|
||||
|
@ -69,7 +69,7 @@ pub enum VagueType {
|
||||
}
|
||||
|
||||
impl TypeKind {
|
||||
pub fn is_known(&self) -> Result<TypeKind, VagueType> {
|
||||
pub fn known(&self) -> Result<TypeKind, VagueType> {
|
||||
if let TypeKind::Vague(vague) = self {
|
||||
Err(*vague)
|
||||
} else {
|
||||
|
@ -107,7 +107,7 @@ impl<T: Clone + std::fmt::Debug> Storage<T> {
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct Scope {
|
||||
pub function_returns: Storage<ScopeFunction>,
|
||||
pub variables: Storage<TypeKind>,
|
||||
pub variables: Storage<ScopeVariable>,
|
||||
/// Hard Return type of this scope, if inside a function
|
||||
pub return_type_hint: Option<TypeKind>,
|
||||
}
|
||||
@ -118,6 +118,12 @@ pub struct ScopeFunction {
|
||||
pub params: Vec<TypeKind>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ScopeVariable {
|
||||
pub ty: TypeKind,
|
||||
pub mutable: bool,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
pub fn inner(&self) -> Scope {
|
||||
Scope {
|
||||
@ -223,7 +229,16 @@ impl Module {
|
||||
impl FunctionDefinition {
|
||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
||||
for param in &self.parameters {
|
||||
scope.variables.set(param.0.clone(), param.1).ok();
|
||||
scope
|
||||
.variables
|
||||
.set(
|
||||
param.0.clone(),
|
||||
ScopeVariable {
|
||||
ty: param.1,
|
||||
mutable: false,
|
||||
},
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
|
||||
pass.function(self, PassState::from(state, scope));
|
||||
@ -268,7 +283,13 @@ impl Statement {
|
||||
match &mut self.0 {
|
||||
StmtKind::Let(variable_reference, mutable, _) => scope
|
||||
.variables
|
||||
.set(variable_reference.1.clone(), variable_reference.0)
|
||||
.set(
|
||||
variable_reference.1.clone(),
|
||||
ScopeVariable {
|
||||
ty: variable_reference.0,
|
||||
mutable: *mutable,
|
||||
},
|
||||
)
|
||||
.ok(),
|
||||
StmtKind::Set(variable_reference, expression) => None, // TODO
|
||||
StmtKind::Import(_) => todo!(),
|
||||
|
@ -7,7 +7,7 @@ use TypeKind::*;
|
||||
use VagueType::*;
|
||||
|
||||
use super::{
|
||||
pass::{Pass, PassState, ScopeFunction},
|
||||
pass::{Pass, PassState, ScopeFunction, ScopeVariable},
|
||||
types::ReturnType,
|
||||
};
|
||||
|
||||
@ -33,6 +33,8 @@ pub enum ErrorKind {
|
||||
FunctionAlreadyDefined(String),
|
||||
#[error("Variable not defined: {0}")]
|
||||
VariableAlreadyDefined(String),
|
||||
#[error("Variable not mutable: {0}")]
|
||||
VariableNotMutable(String),
|
||||
#[error("Function {0} was given {1} parameters, but {2} were expected")]
|
||||
InvalidAmountParameters(String, usize, usize),
|
||||
}
|
||||
@ -59,7 +61,13 @@ impl FunctionDefinition {
|
||||
let res = state
|
||||
.scope
|
||||
.variables
|
||||
.set(param.0.clone(), param_t)
|
||||
.set(
|
||||
param.0.clone(),
|
||||
ScopeVariable {
|
||||
ty: param_t,
|
||||
mutable: false,
|
||||
},
|
||||
)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
||||
state.ok(res, self.signature());
|
||||
}
|
||||
@ -108,9 +116,19 @@ impl Block {
|
||||
variable_reference.2 + expression.1,
|
||||
);
|
||||
|
||||
// Make sure expression/variable type is NOT vague anymore
|
||||
let res_t =
|
||||
state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2);
|
||||
let res_t = if res_t.known().is_err() {
|
||||
// Unable to infer variable type even from expression! Default it
|
||||
let res_t =
|
||||
state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2);
|
||||
|
||||
// Re-typecheck and coerce expression to default type
|
||||
let expr_res = expression.typecheck(&mut state, Some(res_t));
|
||||
state.ok(expr_res, expression.1);
|
||||
|
||||
res_t
|
||||
} else {
|
||||
res_t
|
||||
};
|
||||
|
||||
// Update typing to be more accurate
|
||||
variable_reference.0 = res_t;
|
||||
@ -119,15 +137,56 @@ impl Block {
|
||||
let res = state
|
||||
.scope
|
||||
.variables
|
||||
.set(variable_reference.1.clone(), variable_reference.0)
|
||||
.set(
|
||||
variable_reference.1.clone(),
|
||||
ScopeVariable {
|
||||
ty: variable_reference.0,
|
||||
mutable: *mutable,
|
||||
},
|
||||
)
|
||||
.or(Err(ErrorKind::VariableAlreadyDefined(
|
||||
variable_reference.1.clone(),
|
||||
)));
|
||||
state.ok(res, variable_reference.2);
|
||||
None
|
||||
}
|
||||
StmtKind::Set(variable_reference, expression) => None, // TODO
|
||||
StmtKind::Import(_) => todo!(),
|
||||
StmtKind::Set(variable_reference, expression) => {
|
||||
if let Some(var) = state.scope.variables.get(&variable_reference.1).cloned() {
|
||||
// Typecheck expression and coerce to variable type
|
||||
let res = expression.typecheck(&mut state, Some(var.ty));
|
||||
|
||||
// If expression resolution itself was erronous, resolve as
|
||||
// Unknown.
|
||||
let expr_ty = state.or_else(res, Vague(Unknown), expression.1);
|
||||
|
||||
// Make sure the expression and variable type to really
|
||||
// be the same
|
||||
let res_t = state.or_else(
|
||||
expr_ty.collapse_into(&variable_reference.0),
|
||||
Vague(Unknown),
|
||||
variable_reference.2 + expression.1,
|
||||
);
|
||||
|
||||
// Update typing to be more accurate
|
||||
variable_reference.0 = res_t;
|
||||
|
||||
if !var.mutable {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::VariableNotMutable(variable_reference.1.clone())),
|
||||
variable_reference.2,
|
||||
);
|
||||
}
|
||||
|
||||
None
|
||||
} else {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::VariableNotDefined(variable_reference.1.clone())),
|
||||
variable_reference.2,
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
StmtKind::Import(_) => todo!(), // TODO
|
||||
StmtKind::Expression(expression) => {
|
||||
let res = expression.typecheck(&mut state, None);
|
||||
state.or_else(res, Void, expression.1);
|
||||
@ -180,7 +239,8 @@ impl Expression {
|
||||
.scope
|
||||
.variables
|
||||
.get(&var_ref.1)
|
||||
.copied()
|
||||
.map(|var| &var.ty)
|
||||
.cloned()
|
||||
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())),
|
||||
Vague(Unknown),
|
||||
var_ref.2,
|
||||
@ -341,7 +401,7 @@ impl TypeKind {
|
||||
/// Assert that a type is already known and not vague. Return said type or
|
||||
/// error.
|
||||
fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
|
||||
self.is_known().map_err(ErrorKind::TypeIsVague)
|
||||
self.known().map_err(ErrorKind::TypeIsVague)
|
||||
}
|
||||
|
||||
/// Try to collapse a type on itself producing a default type if one exists,
|
||||
|
Loading…
Reference in New Issue
Block a user