(broken) add part 1 of mutability
This commit is contained in:
parent
85b2ebf04a
commit
14e0dcbe15
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
|
use llvm_sys::core::{LLVMBuildAlloca, LLVMBuildLoad2, LLVMBuildStore};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type,
|
BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type,
|
||||||
util::match_types,
|
util::match_types,
|
||||||
@ -250,6 +252,29 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Alloca(_, _) => Ok(()),
|
||||||
|
Load(ptr, _) => {
|
||||||
|
if let Ok(ty) = ptr.get_type(&self) {
|
||||||
|
if let Type::Ptr(_) = ty {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Store(ptr, _) => {
|
||||||
|
if let Ok(ty) = ptr.get_type(&self) {
|
||||||
|
if let Type::Ptr(_) = ty {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,7 +323,7 @@ impl InstructionValue {
|
|||||||
.function_data(&self.0.0)
|
.function_data(&self.0.0)
|
||||||
.params
|
.params
|
||||||
.get(*nth)
|
.get(*nth)
|
||||||
.copied()
|
.cloned()
|
||||||
.ok_or(()),
|
.ok_or(()),
|
||||||
Constant(c) => Ok(c.get_type()),
|
Constant(c) => Ok(c.get_type()),
|
||||||
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
@ -308,6 +333,9 @@ impl InstructionValue {
|
|||||||
ICmp(_, _, _) => Ok(Type::Bool),
|
ICmp(_, _, _) => Ok(Type::Bool),
|
||||||
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
||||||
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)),
|
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)),
|
||||||
|
Alloca(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
||||||
|
Load(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
||||||
|
Store(_, value) => value.get_type(builder),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,6 +375,7 @@ impl Type {
|
|||||||
Type::U128 => true,
|
Type::U128 => true,
|
||||||
Type::Bool => true,
|
Type::Bool => true,
|
||||||
Type::Void => false,
|
Type::Void => false,
|
||||||
|
Type::Ptr(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,6 +393,7 @@ impl Type {
|
|||||||
Type::U128 => false,
|
Type::U128 => false,
|
||||||
Type::Bool => false,
|
Type::Bool => false,
|
||||||
Type::Void => false,
|
Type::Void => false,
|
||||||
|
Type::Ptr(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,6 +333,22 @@ impl InstructionHolder {
|
|||||||
);
|
);
|
||||||
phi
|
phi
|
||||||
}
|
}
|
||||||
|
Alloca(name, ty) => LLVMBuildAlloca(
|
||||||
|
module.builder_ref,
|
||||||
|
ty.as_llvm(module.context_ref),
|
||||||
|
into_cstring(name).as_ptr(),
|
||||||
|
),
|
||||||
|
Load(ptr, ty) => LLVMBuildLoad2(
|
||||||
|
module.builder_ref,
|
||||||
|
ty.as_llvm(module.context_ref),
|
||||||
|
module.values.get(&ptr).unwrap().value_ref,
|
||||||
|
c"load".as_ptr(),
|
||||||
|
),
|
||||||
|
Store(ptr, val) => LLVMBuildStore(
|
||||||
|
module.builder_ref,
|
||||||
|
module.values.get(&val).unwrap().value_ref,
|
||||||
|
module.values.get(&ptr).unwrap().value_ref,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LLVMValue {
|
LLVMValue {
|
||||||
@ -428,6 +444,7 @@ impl Type {
|
|||||||
I128 | U128 => LLVMInt128TypeInContext(context),
|
I128 | U128 => LLVMInt128TypeInContext(context),
|
||||||
Bool => LLVMInt1TypeInContext(context),
|
Bool => LLVMInt1TypeInContext(context),
|
||||||
Void => LLVMVoidType(),
|
Void => LLVMVoidType(),
|
||||||
|
Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,9 @@ impl Debug for Instr {
|
|||||||
Self::Phi(val) => fmt_call(f, &"Phi", &val),
|
Self::Phi(val) => fmt_call(f, &"Phi", &val),
|
||||||
Self::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
|
Self::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
|
||||||
Self::FunctionCall(fun, params) => fmt_call(f, fun, params),
|
Self::FunctionCall(fun, params) => fmt_call(f, fun, params),
|
||||||
|
Instr::Alloca(name, ty) => write!(f, "alloca<{:?}>({})", ty, name),
|
||||||
|
Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val),
|
||||||
|
Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,13 +174,17 @@ pub enum Instr {
|
|||||||
And(InstructionValue, InstructionValue),
|
And(InstructionValue, InstructionValue),
|
||||||
Phi(Vec<InstructionValue>),
|
Phi(Vec<InstructionValue>),
|
||||||
|
|
||||||
|
Alloca(String, Type),
|
||||||
|
Load(InstructionValue, Type),
|
||||||
|
Store(InstructionValue, InstructionValue),
|
||||||
|
|
||||||
/// Integer Comparison
|
/// Integer Comparison
|
||||||
ICmp(CmpPredicate, InstructionValue, InstructionValue),
|
ICmp(CmpPredicate, InstructionValue, InstructionValue),
|
||||||
|
|
||||||
FunctionCall(FunctionValue, Vec<InstructionValue>),
|
FunctionCall(FunctionValue, Vec<InstructionValue>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
I8,
|
I8,
|
||||||
I16,
|
I16,
|
||||||
@ -194,6 +198,7 @@ pub enum Type {
|
|||||||
U128,
|
U128,
|
||||||
Bool,
|
Bool,
|
||||||
Void,
|
Void,
|
||||||
|
Ptr(Box<Type>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
@ -133,7 +133,7 @@ pub struct Block(
|
|||||||
pub enum BlockLevelStatement {
|
pub enum BlockLevelStatement {
|
||||||
Let(LetStatement),
|
Let(LetStatement),
|
||||||
/// Try to set a variable to a specified expression value
|
/// Try to set a variable to a specified expression value
|
||||||
Set(String, Expression),
|
Set(String, Expression, TokenRange),
|
||||||
Import {
|
Import {
|
||||||
_i: ImportStatement,
|
_i: ImportStatement,
|
||||||
},
|
},
|
||||||
|
@ -363,8 +363,8 @@ impl Parse for BlockLevelStatement {
|
|||||||
Stmt::Return(ReturnType::Hard, exp)
|
Stmt::Return(ReturnType::Hard, exp)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Ok(SetStatement(ident, expr)) = stream.parse() {
|
if let Ok(SetStatement(ident, expr, range)) = stream.parse() {
|
||||||
Stmt::Set(ident, expr)
|
Stmt::Set(ident, expr, range)
|
||||||
} else {
|
} else {
|
||||||
if let Ok(e) = stream.parse() {
|
if let Ok(e) = stream.parse() {
|
||||||
if stream.expect(Token::Semi).is_ok() {
|
if stream.expect(Token::Semi).is_ok() {
|
||||||
@ -382,7 +382,7 @@ impl Parse for BlockLevelStatement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SetStatement(String, Expression);
|
pub struct SetStatement(String, Expression, TokenRange);
|
||||||
|
|
||||||
impl Parse for SetStatement {
|
impl Parse for SetStatement {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
@ -390,7 +390,7 @@ impl Parse for SetStatement {
|
|||||||
stream.expect(Token::Equals)?;
|
stream.expect(Token::Equals)?;
|
||||||
let expr = stream.parse()?;
|
let expr = stream.parse()?;
|
||||||
stream.expect(Token::Semi)?;
|
stream.expect(Token::Semi)?;
|
||||||
Ok(Self(ident, expr))
|
Ok(Self(ident, expr, stream.get_range().unwrap()))
|
||||||
} else {
|
} else {
|
||||||
Err(stream.expected_err("identifier")?)?
|
Err(stream.expected_err("identifier")?)?
|
||||||
}
|
}
|
||||||
|
@ -70,11 +70,22 @@ impl ast::Block {
|
|||||||
s_let.0.clone(),
|
s_let.0.clone(),
|
||||||
s_let.4.into(),
|
s_let.4.into(),
|
||||||
),
|
),
|
||||||
|
s_let.2,
|
||||||
s_let.3.process(),
|
s_let.3.process(),
|
||||||
),
|
),
|
||||||
s_let.4,
|
s_let.4,
|
||||||
),
|
),
|
||||||
ast::BlockLevelStatement::Set(_, expression) => todo!(),
|
ast::BlockLevelStatement::Set(name, expression, range) => (
|
||||||
|
StmtKind::Set(
|
||||||
|
VariableReference(
|
||||||
|
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
|
name.clone(),
|
||||||
|
(*range).into(),
|
||||||
|
),
|
||||||
|
expression.process(),
|
||||||
|
),
|
||||||
|
*range,
|
||||||
|
),
|
||||||
ast::BlockLevelStatement::Import { _i } => todo!(),
|
ast::BlockLevelStatement::Import { _i } => todo!(),
|
||||||
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
|
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
|
||||||
ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1),
|
ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1),
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use std::{collections::HashMap, mem};
|
use std::{collections::HashMap, mem};
|
||||||
|
|
||||||
|
use llvm_sys::core::LLVMBuildStore;
|
||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
Block, CmpPredicate, ConstValue, Context, Function, Instr, Module, TerminatorKind as Term,
|
builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, Instr, Module,
|
||||||
Type, builder::InstructionValue,
|
TerminatorKind as Term, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::{self, TypeKind, VariableReference, types::ReturnType};
|
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
||||||
|
|
||||||
/// Context that contains all of the given modules as complete codegenerated
|
/// Context that contains all of the given modules as complete codegenerated
|
||||||
/// LLIR that can then be finally compiled into LLVM IR.
|
/// LLIR that can then be finally compiled into LLVM IR.
|
||||||
@ -73,8 +74,14 @@ impl mir::Module {
|
|||||||
let mut entry = function.block("entry");
|
let mut entry = function.block("entry");
|
||||||
|
|
||||||
let mut stack_values = HashMap::new();
|
let mut stack_values = HashMap::new();
|
||||||
for (i, (p_name, _)) in mir_function.parameters.iter().enumerate() {
|
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
|
||||||
stack_values.insert(p_name.clone(), entry.build(Instr::Param(i)).unwrap());
|
stack_values.insert(
|
||||||
|
p_name.clone(),
|
||||||
|
StackValue(
|
||||||
|
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
|
||||||
|
p_ty.get_type(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut scope = Scope {
|
let mut scope = Scope {
|
||||||
@ -114,7 +121,16 @@ pub struct Scope<'ctx, 'a> {
|
|||||||
function: &'ctx Function<'ctx>,
|
function: &'ctx Function<'ctx>,
|
||||||
block: Block<'ctx>,
|
block: Block<'ctx>,
|
||||||
functions: &'a HashMap<String, Function<'ctx>>,
|
functions: &'a HashMap<String, Function<'ctx>>,
|
||||||
stack_values: HashMap<String, InstructionValue>,
|
stack_values: HashMap<String, StackValue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct StackValue(StackValueKind, Type);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum StackValueKind {
|
||||||
|
Immutable(InstructionValue),
|
||||||
|
Mutable(InstructionValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx, 'a> Scope<'ctx, 'a> {
|
impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||||
@ -141,11 +157,33 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
|||||||
impl mir::Statement {
|
impl mir::Statement {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
mir::StmtKind::Let(VariableReference(_, name, _), expression) => {
|
mir::StmtKind::Let(VariableReference(ty, name, _), mutable, expression) => {
|
||||||
let value = expression.codegen(scope).unwrap();
|
let value = expression.codegen(scope).unwrap();
|
||||||
scope.stack_values.insert(name.clone(), value);
|
scope.stack_values.insert(
|
||||||
|
name.clone(),
|
||||||
|
StackValue(
|
||||||
|
match mutable {
|
||||||
|
true => StackValueKind::Mutable(value),
|
||||||
|
false => StackValueKind::Immutable(value),
|
||||||
|
},
|
||||||
|
ty.get_type(),
|
||||||
|
),
|
||||||
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
mir::StmtKind::Set(var, val) => {
|
||||||
|
if let Some(StackValue(kind, ty)) = scope.stack_values.get(&var.1).cloned() {
|
||||||
|
match kind {
|
||||||
|
StackValueKind::Immutable(ptr) => {
|
||||||
|
let expression = val.codegen(scope).unwrap();
|
||||||
|
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
|
||||||
|
}
|
||||||
|
StackValueKind::Mutable(_) => panic!(""),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
// mir::StmtKind::If(if_expression) => if_expression.codegen(scope),
|
// mir::StmtKind::If(if_expression) => if_expression.codegen(scope),
|
||||||
mir::StmtKind::Import(_) => todo!(),
|
mir::StmtKind::Import(_) => todo!(),
|
||||||
mir::StmtKind::Expression(expression) => expression.codegen(scope),
|
mir::StmtKind::Expression(expression) => expression.codegen(scope),
|
||||||
@ -218,7 +256,12 @@ impl mir::Expression {
|
|||||||
.stack_values
|
.stack_values
|
||||||
.get(&varref.1)
|
.get(&varref.1)
|
||||||
.expect("Variable reference not found?!");
|
.expect("Variable reference not found?!");
|
||||||
Some(v.clone())
|
Some(match v.0 {
|
||||||
|
StackValueKind::Immutable(val) => val.clone(),
|
||||||
|
StackValueKind::Mutable(val) => {
|
||||||
|
scope.block.build(Instr::Load(val, v.1.clone())).unwrap()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
|
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
|
||||||
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
||||||
|
@ -94,7 +94,16 @@ impl Display for Statement {
|
|||||||
impl Display for StmtKind {
|
impl Display for StmtKind {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Let(var, block) => write!(f, "let {} = {}", var, block),
|
Self::Let(var, mutable, block) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"let{} {} = {}",
|
||||||
|
if *mutable { " mut" } else { "" },
|
||||||
|
var,
|
||||||
|
block
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Set(var, expr) => write!(f, "{} = {}", var, expr),
|
||||||
Self::Import(n) => write!(f, "import {}", n),
|
Self::Import(n) => write!(f, "import {}", n),
|
||||||
Self::Expression(exp) => Display::fmt(exp, f),
|
Self::Expression(exp) => Display::fmt(exp, f),
|
||||||
}
|
}
|
||||||
|
@ -257,8 +257,9 @@ pub struct Statement(pub StmtKind, pub Metadata);
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum StmtKind {
|
pub enum StmtKind {
|
||||||
/// Variable name+type, evaluation
|
/// Variable name++mutability+type, evaluation
|
||||||
Let(VariableReference, Expression),
|
Let(VariableReference, bool, Expression),
|
||||||
|
Set(VariableReference, Expression),
|
||||||
Import(Import),
|
Import(Import),
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
}
|
}
|
||||||
|
@ -253,9 +253,10 @@ impl Block {
|
|||||||
impl Statement {
|
impl Statement {
|
||||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
StmtKind::Let(_, expression) => {
|
StmtKind::Let(_, mutable, expression) => {
|
||||||
expression.pass(pass, state, scope);
|
expression.pass(pass, state, scope);
|
||||||
}
|
}
|
||||||
|
StmtKind::Set(variable_reference, expression) => {} // TODO
|
||||||
StmtKind::Import(_) => todo!(),
|
StmtKind::Import(_) => todo!(),
|
||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
expression.pass(pass, state, scope);
|
expression.pass(pass, state, scope);
|
||||||
@ -265,10 +266,11 @@ impl Statement {
|
|||||||
pass.stmt(self, PassState::from(state, scope));
|
pass.stmt(self, PassState::from(state, scope));
|
||||||
|
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
StmtKind::Let(variable_reference, _) => scope
|
StmtKind::Let(variable_reference, mutable, _) => scope
|
||||||
.variables
|
.variables
|
||||||
.set(variable_reference.1.clone(), variable_reference.0)
|
.set(variable_reference.1.clone(), variable_reference.0)
|
||||||
.ok(),
|
.ok(),
|
||||||
|
StmtKind::Set(variable_reference, expression) => None, // TODO
|
||||||
StmtKind::Import(_) => todo!(),
|
StmtKind::Import(_) => todo!(),
|
||||||
StmtKind::Expression(_) => None,
|
StmtKind::Expression(_) => None,
|
||||||
};
|
};
|
||||||
|
@ -93,7 +93,8 @@ impl Block {
|
|||||||
|
|
||||||
for statement in &mut self.statements {
|
for statement in &mut self.statements {
|
||||||
let ret = match &mut statement.0 {
|
let ret = match &mut statement.0 {
|
||||||
StmtKind::Let(variable_reference, expression) => {
|
// TODO
|
||||||
|
StmtKind::Let(variable_reference, mutable, expression) => {
|
||||||
let res = expression.typecheck(&mut state, Some(variable_reference.0));
|
let res = expression.typecheck(&mut state, Some(variable_reference.0));
|
||||||
|
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
@ -125,6 +126,7 @@ impl Block {
|
|||||||
state.ok(res, variable_reference.2);
|
state.ok(res, variable_reference.2);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
StmtKind::Set(variable_reference, expression) => None, // TODO
|
||||||
StmtKind::Import(_) => todo!(),
|
StmtKind::Import(_) => todo!(),
|
||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
let res = expression.typecheck(&mut state, None);
|
let res = expression.typecheck(&mut state, None);
|
||||||
|
@ -26,8 +26,9 @@ impl ReturnType for Statement {
|
|||||||
use StmtKind::*;
|
use StmtKind::*;
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
Expression(e) => e.return_type(),
|
Expression(e) => e.return_type(),
|
||||||
|
Set(_, _) => todo!(),
|
||||||
Import(_) => Err(ReturnTypeOther::Import(self.1.range)),
|
Import(_) => Err(ReturnTypeOther::Import(self.1.range)),
|
||||||
Let(_, _) => Err(ReturnTypeOther::Let(self.1.range)),
|
Let(_, _, _) => Err(ReturnTypeOther::Let(self.1.range)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user