pushing to move code
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
// mod types;
|
// mod types;
|
||||||
mod ast;
|
mod ast;
|
||||||
mod type_alias_resolution;
|
mod type_alias_resolution;
|
||||||
|
mod type_checking;
|
||||||
#[macro_use] extern crate lalrpop_util;
|
#[macro_use] extern crate lalrpop_util;
|
||||||
|
|
||||||
lalrpop_mod!(pub grammar); // synthesized by LALRPOP
|
lalrpop_mod!(pub grammar); // synthesized by LALRPOP
|
||||||
@@ -44,8 +45,11 @@ fn main() {
|
|||||||
println!("ast: {:#?}", &module_ast);
|
println!("ast: {:#?}", &module_ast);
|
||||||
let alias_resolver = type_alias_resolution::TypeAliasResolver{};
|
let alias_resolver = type_alias_resolution::TypeAliasResolver{};
|
||||||
let resolved_ast = alias_resolver.with_module(&module_ast);
|
let resolved_ast = alias_resolver.with_module(&module_ast);
|
||||||
println!("ast: {:#?}", &resolved_ast);
|
println!("resolved ast: {:#?}", &resolved_ast);
|
||||||
|
let type_checker = type_checking::TypeChecker{};
|
||||||
|
let (checked_ast, subst) = type_checker.with_module(&resolved_ast);
|
||||||
|
println!("checked ast: {:#?}", &resolved_ast);
|
||||||
|
println!("substitutions: {:#?}", &subst);
|
||||||
|
|
||||||
// let context = Context::create();
|
// let context = Context::create();
|
||||||
// let mut code_gen = compiler::ModuleCodeGen::new(&context, "main".to_string());
|
// let mut code_gen = compiler::ModuleCodeGen::new(&context, "main".to_string());
|
||||||
|
|||||||
@@ -2,19 +2,40 @@ use std::collections::HashMap;
|
|||||||
use crate::ast;
|
use crate::ast;
|
||||||
|
|
||||||
|
|
||||||
type SubstitutionMap = HashMap<String, ast::TypeUsage>;
|
pub type SubstitutionMap = HashMap<String, ast::TypeUsage>;
|
||||||
|
|
||||||
pub enum NamedEntity {
|
pub enum NamedEntity {
|
||||||
Types(ast::TypeDeclaration),
|
TypeDeclaration(ast::TypeDeclaration),
|
||||||
Values(ast::Value),
|
Variable(ast::TypeUsage),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
struct Context {
|
struct Context {
|
||||||
|
pub current_function_return: Option<ast::TypeUsage>,
|
||||||
pub environment: HashMap<String, ast::NamedEntity>,
|
pub environment: HashMap<String, ast::NamedEntity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
fn add_variable(&self, name: String, type_usage: &ast::TypeUsage) -> Context {
|
||||||
|
let mut ctx = self.clone();
|
||||||
|
ctx.environment[name] = NamedEntity::Variable(type_usage.clone());
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_type(&self, name: String, type_decl: &ast::TypeDeclaration) -> Context {
|
||||||
|
let mut ctx = self.clone();
|
||||||
|
ctx.environment[name] = NamedEntity::TypeDeclaration(type_decl.clone());
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_current_function_return(&self, function: ast::TypeUsage) -> Context {
|
||||||
|
let mut ctx = self.clone();
|
||||||
|
ctx.current_function_return = Some(function);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn apply_substitution(substitution: &SubstitutionMap, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
fn apply_substitution(substitution: &SubstitutionMap, type_: &ast::TypeUsage) -> ast::TypeUsage {
|
||||||
match type_ {
|
match type_ {
|
||||||
ast::TypeUsage::Named(named) => ast::TypeUsage::Named(named.clone()),
|
ast::TypeUsage::Named(named) => ast::TypeUsage::Named(named.clone()),
|
||||||
@@ -113,7 +134,7 @@ fn contains(t: ast::TypeUsage, name: &str) -> bool {
|
|||||||
pub struct TypeChecker {}
|
pub struct TypeChecker {}
|
||||||
|
|
||||||
impl TypeChecker {
|
impl TypeChecker {
|
||||||
pub fn with_module(self: &Self, module: &ast::Module) -> ast::Module {
|
pub fn with_module(self: &Self, module: &ast::Module) -> (ast::Module, SubstitutionMap) {
|
||||||
let mut ctx = Context{
|
let mut ctx = Context{
|
||||||
environment: HashMap::new(), //TODO: builtins
|
environment: HashMap::new(), //TODO: builtins
|
||||||
};
|
};
|
||||||
@@ -121,10 +142,10 @@ impl TypeChecker {
|
|||||||
for item in module.items.iter() {
|
for item in module.items.iter() {
|
||||||
match item {
|
match item {
|
||||||
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Struct(struct_)) => {
|
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Struct(struct_)) => {
|
||||||
ctx.declarations.push(ast::NamedEntity::Types(ast::TypeDeclaration::Struct(struct_.clone())));
|
ctx.declarations.push(ast::NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(struct_.clone())));
|
||||||
},
|
},
|
||||||
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Alias(alias)) => {
|
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Alias(alias)) => {
|
||||||
ctx.declarations.push(ast::NamedEntity::Types(ast::TypeDeclaration::Alias(alias.clone())));
|
ctx.declarations.push(ast::NamedEntity::TypeDeclaration(ast::TypeDeclaration::Alias(alias.clone())));
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
@@ -149,33 +170,37 @@ impl TypeChecker {
|
|||||||
|
|
||||||
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> (ast::Function, SubstitutionMap) {
|
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> (ast::Function, SubstitutionMap) {
|
||||||
// add args to env
|
// add args to env
|
||||||
|
let mut function_ctx = ctx.set_current_function_return(function.declaration.return_type.clone());
|
||||||
|
for arg in function.declaration.arguments.iter() {
|
||||||
|
function_ctx = function_ctx.add_variable(arg.name.to_string(), arg.type_.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let (block, substitution) = self.with_block(ctx, &function.block);
|
let (block, substitution) = self.with_block(function_ctx, &function.block);
|
||||||
// if block.type_ is not never
|
|
||||||
let substitution = unify(block.type_, function.declaration.return_type);
|
let substitution = unify(block.type_, function.declaration.return_type);
|
||||||
|
|
||||||
return ast::Function{
|
return (ast::Function{
|
||||||
declaration: ast::FunctionDeclaration{
|
declaration: ast::FunctionDeclaration{
|
||||||
name: function.declaration.name.clone(),
|
name: function.declaration.name.clone(),
|
||||||
arguments: function.declaration.arguments.iter().map(|arg| {
|
arguments: function.declaration.arguments.iter().map(|arg| {
|
||||||
ast::VariableDeclaration{name: arg.name.clone(), type_: process_type(ctx, &arg.type_)}
|
arg.clone()
|
||||||
}).collect(),
|
}).collect(),
|
||||||
return_type: apply_substitution(substitution, function.declaration.return_type),
|
return_type: function.declaration.return_type.clone(),
|
||||||
},
|
},
|
||||||
block: block,
|
block: block,
|
||||||
};
|
}, substitution);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> ast::TypeDeclaration {
|
fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> (ast::TypeDeclaration, SubstitutionMap) {
|
||||||
match type_declaration {
|
match type_declaration {
|
||||||
ast::TypeDeclaration::Struct(struct_) => {
|
ast::TypeDeclaration::Struct(struct_) => {
|
||||||
return ast::TypeDeclaration::Struct(self.with_struct_declaration(ctx, struct_));
|
let (result, substitution) = self.with_struct_declaration(ctx, struct_);
|
||||||
|
return (ast::TypeDeclaration::Struct(result), substitution);
|
||||||
},
|
},
|
||||||
ast::TypeDeclaration::Primitive(primitive) => {
|
ast::TypeDeclaration::Primitive(primitive) => {
|
||||||
return ast::TypeDeclaration::Primitive(primitive.clone());
|
return (ast::TypeDeclaration::Primitive(primitive.clone()), SubstitutionMap::new());
|
||||||
},
|
},
|
||||||
ast::TypeDeclaration::Alias(alias) => {
|
ast::TypeDeclaration::Alias(alias) => {
|
||||||
return ast::TypeDeclaration::Alias(alias.clone());
|
return (ast::TypeDeclaration::Alias(alias.clone()), SubstitutionMap::new());
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,148 +211,181 @@ impl TypeChecker {
|
|||||||
fields: struct_.fields.iter().map(|field|{
|
fields: struct_.fields.iter().map(|field|{
|
||||||
ast::StructField{
|
ast::StructField{
|
||||||
name: field.name.clone(),
|
name: field.name.clone(),
|
||||||
type_: process_type(ctx, &field.type_),
|
type_: field.type_.clone(),
|
||||||
}
|
}
|
||||||
}).collect(),
|
}).collect(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> ast::Impl {
|
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> (ast::Impl, SubstitutionMap) {
|
||||||
let mut impl_ctx = ctx.clone();
|
let mut substitutions = SubstitutionMap::new();
|
||||||
impl_ctx.type_aliases.push(ast::AliasTypeDeclaration{
|
return (ast::Impl{
|
||||||
name: ast::Identifier{
|
|
||||||
name: ast::Spanned{
|
|
||||||
span: ast::Span{left: 0, right: 0}, //todo: figure out a sane value for these
|
|
||||||
value: "Self".to_string(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage{name: impl_.struct_name.clone()})
|
|
||||||
});
|
|
||||||
return ast::Impl{
|
|
||||||
struct_name: impl_.struct_name.clone(),
|
struct_name: impl_.struct_name.clone(),
|
||||||
functions: impl_.functions.iter().map(|f|{
|
functions: impl_.functions.iter().map(|f|{
|
||||||
self.with_function(&impl_ctx, f)
|
let (result, function_subs) = self.with_function(&ctx, f);
|
||||||
|
substitutions = compose_substitutions(substitutions, function_subs)
|
||||||
|
result
|
||||||
}).collect(),
|
}).collect(),
|
||||||
};
|
}, substitutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> ast::Block {
|
fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> (ast::Block, SubstitutionMap) {
|
||||||
|
let mut substitutions = SubstitutionMap::new();
|
||||||
|
let mut block_ctx = ctx.clone();
|
||||||
return ast::Block{
|
return ast::Block{
|
||||||
statements: block.statements.iter().map(|s| {
|
statements: block.statements.iter().map(|s| {
|
||||||
self.with_statement(ctx, s)
|
let (statement_ctx, result, statement_substitutions) = self.with_statement(block_ctx, s);
|
||||||
|
block_ctx = statement_ctx
|
||||||
|
substitutions = compose_substitutions(substitutions, statement_substitutions);
|
||||||
|
result
|
||||||
}).collect(),
|
}).collect(),
|
||||||
type_: process_type(ctx, &block.type_),
|
type_: block.type_.clone(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_statement(self: &Self, ctx: &Context, statement: &ast::Statement) -> ast::Statement {
|
fn with_statement(self: &Self, ctx: &Context, statement: &ast::Statement) -> (Context, ast::Statement, SubstitutionMap) {
|
||||||
|
|
||||||
match statement {
|
match statement {
|
||||||
ast::Statement::Return(return_statement) => {
|
ast::Statement::Return(return_statement) => {
|
||||||
return ast::Statement::Return(self.with_return_statement(ctx, return_statement));
|
let (result, subst) = self.with_return_statement(ctx, return_statement);
|
||||||
|
return (ctx.clone(), ast::Statement::Return(result), subst);
|
||||||
},
|
},
|
||||||
ast::Statement::Let(let_statement) => {
|
ast::Statement::Let(let_statement) => {
|
||||||
return ast::Statement::Let(self.with_let_statement(ctx, let_statement));
|
let (let_ctx, result, subst) = self.with_let_statement(ctx, let_statement);
|
||||||
|
return (let_ctx, ast::Statement::Let(result), subst);
|
||||||
},
|
},
|
||||||
ast::Statement::Assignment(assignment_statement) => {
|
ast::Statement::Assignment(assignment_statement) => {
|
||||||
return ast::Statement::Assignment(self.with_assignment_statement(ctx, assignment_statement));
|
let (result, subst) = self.with_assignment_statement(ctx, assignment_statement);
|
||||||
|
return (ctx.clone(), ast::Statement::Assignment(result), subst);
|
||||||
},
|
},
|
||||||
ast::Statement::Expression(expression) => {
|
ast::Statement::Expression(expression) => {
|
||||||
return ast::Statement::Expression(self.with_expression(ctx, expression));
|
let (result, subst) = self.with_expression(ctx, expression);
|
||||||
|
return (ctx.clone(), ast::Statement::Expression(result), subst);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> ast::ReturnStatement {
|
fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> (ast::ReturnStatement, SubstitutionMap) {
|
||||||
return ast::ReturnStatement{
|
let (result, subst) = self.with_expression(ctx, &statement.source);
|
||||||
source: self.with_expression(ctx, &statement.source),
|
let substitution = compose_substitutions(subst, unify(result.type_, ctx.current_function_return));
|
||||||
};
|
return (ast::ReturnStatement{
|
||||||
|
source: result,
|
||||||
|
}, substitution);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> ast::LetStatement {
|
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> (Context, ast::LetStatement, SubstitutionMap) {
|
||||||
return ast::LetStatement{
|
let (result, subst) = self.with_expression(ctx, &statement.expression);
|
||||||
|
let let_ctx = ctx.add_variable(statement.variable_name.clone(), result.type_);
|
||||||
|
let substitution = compose_substitutions(subst, unify(&statement.type_, result.type_));
|
||||||
|
return (let_ctx, ast::LetStatement{
|
||||||
variable_name: statement.variable_name.clone(),
|
variable_name: statement.variable_name.clone(),
|
||||||
expression: self.with_expression(ctx, &statement.expression),
|
expression: result,
|
||||||
type_: process_type(ctx, &statement.type_),
|
type_: &statement.type_.clone(),
|
||||||
};
|
}, substitution);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> ast::AssignmentStatement {
|
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> ast::AssignmentStatement {
|
||||||
|
|
||||||
return ast::AssignmentStatement{
|
return ast::AssignmentStatement{
|
||||||
source: match &statement.source {
|
source: match &statement.source {
|
||||||
ast::AssignmentTarget::Variable(variable) => {
|
ast::AssignmentTarget::Variable(variable) => {
|
||||||
ast::AssignmentTarget::Variable(ast::VariableUsage{
|
let assignment_subs = compose_substitutions(subs, unify(&expr.type_, &variable.type_));
|
||||||
|
(ast::AssignmentTarget::Variable(ast::VariableUsage{
|
||||||
name: variable.name.clone(),
|
name: variable.name.clone(),
|
||||||
type_: process_type(ctx, &variable.type_),
|
type_: &variable.type_.clone(),
|
||||||
})
|
}), assignment_subs)
|
||||||
},
|
},
|
||||||
ast::AssignmentTarget::StructAttr(struct_attr) => {
|
ast::AssignmentTarget::StructAttr(struct_attr) => {
|
||||||
ast::AssignmentTarget::StructAttr(ast::StructGetter{
|
// let assignment_subs = compose_substitutions(subs, unify(&expr.type_, &struct_attr.type_));
|
||||||
source: self.with_expression(ctx, &struct_attr.source),
|
let (expr, subst) = self.with_expression(ctx, &struct_attr.source);
|
||||||
|
|
||||||
|
(ast::AssignmentTarget::StructAttr(ast::StructGetter{
|
||||||
|
source: expr,
|
||||||
attribute: struct_attr.attribute.clone(),
|
attribute: struct_attr.attribute.clone(),
|
||||||
type_: process_type(ctx, &struct_attr.type_)
|
type_: &struct_attr.type_.clone(),
|
||||||
})
|
}), subst)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expression: self.with_expression(ctx, &statement.expression),
|
expression: expr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> ast::Expression {
|
fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> (ast::Expression, SubstitutionMap) {
|
||||||
return ast::Expression{
|
let mut substitution = SubstitutionMap::new();
|
||||||
|
let expr = ast::Expression{
|
||||||
subexpression: Box::new(match &*expression.subexpression {
|
subexpression: Box::new(match &*expression.subexpression {
|
||||||
ast::Subexpression::LiteralInt(literal_int) => {
|
ast::Subexpression::LiteralInt(literal_int) => {
|
||||||
ast::Subexpression::LiteralInt(ast::LiteralInt{
|
ast::Subexpression::LiteralInt(ast::LiteralInt{
|
||||||
value: literal_int.value.clone(),
|
value: literal_int.value.clone(),
|
||||||
type_: process_type(ctx, &literal_int.type_),
|
type_: literal_int.type_.clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ast::Subexpression::LiteralFloat(literal_float) => {
|
ast::Subexpression::LiteralFloat(literal_float) => {
|
||||||
ast::Subexpression::LiteralFloat(ast::LiteralFloat{
|
ast::Subexpression::LiteralFloat(ast::LiteralFloat{
|
||||||
value: literal_float.value.clone(),
|
value: literal_float.value.clone(),
|
||||||
type_: process_type(ctx, &literal_float.type_),
|
type_: literal_float.type_.clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ast::Subexpression::LiteralStruct(literal_struct) => {
|
ast::Subexpression::LiteralStruct(literal_struct) => {
|
||||||
ast::Subexpression::LiteralStruct(ast::LiteralStruct{
|
ast::Subexpression::LiteralStruct(ast::LiteralStruct{
|
||||||
name: literal_struct.name.clone(),
|
name: literal_struct.name.clone(),
|
||||||
fields: literal_struct.fields.iter().map(|field|{
|
fields: literal_struct.fields.iter().map(|field|{
|
||||||
|
|
||||||
|
// substitution = compose_substitutions(substitution, );
|
||||||
(field.0.clone(), self.with_expression(ctx, &field.1))
|
(field.0.clone(), self.with_expression(ctx, &field.1))
|
||||||
}).collect(),
|
}).collect(),
|
||||||
type_: process_type(ctx, &literal_struct.type_),
|
type_: literal_struct.type_.clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ast::Subexpression::FunctionCall(function_call) => {
|
ast::Subexpression::FunctionCall(function_call) => {
|
||||||
ast::Subexpression::FunctionCall(ast::FunctionCall{
|
ast::Subexpression::FunctionCall(ast::FunctionCall{
|
||||||
source: self.with_expression(ctx, &function_call.source),
|
source: self.with_expression(ctx, &function_call.source),
|
||||||
arguments: function_call.arguments.iter().map(|arg| {self.with_expression(ctx, arg)}).collect(),
|
arguments: function_call.arguments.iter().map(|arg| {self.with_expression(ctx, arg)}).collect(),
|
||||||
type_: process_type(ctx, &function_call.type_)
|
type_: function_call.type_.clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ast::Subexpression::VariableUsage(variable_usage) => {
|
ast::Subexpression::VariableUsage(variable_usage) => {
|
||||||
|
match ctx.environment[variable_usage.name] {
|
||||||
|
NamedEntity::TypeDeclaration(_) => {
|
||||||
|
panic!("Using types not yet supported");
|
||||||
|
},
|
||||||
|
NamedEntity::Variable(variable) => {
|
||||||
|
substitution = compose_substitutions(substitution, unify(variable, expression.type_));
|
||||||
|
},
|
||||||
|
}
|
||||||
ast::Subexpression::VariableUsage(ast::VariableUsage{
|
ast::Subexpression::VariableUsage(ast::VariableUsage{
|
||||||
name: variable_usage.name.clone(),
|
name: variable_usage.name.clone(),
|
||||||
type_: process_type(ctx, &variable_usage.type_)
|
type_: variable_usage.type_.clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ast::Subexpression::StructGetter(struct_getter) => {
|
ast::Subexpression::StructGetter(struct_getter) => {
|
||||||
ast::Subexpression::StructGetter(ast::StructGetter{
|
ast::Subexpression::StructGetter(ast::StructGetter{
|
||||||
source: self.with_expression(ctx, &struct_getter.source),
|
source: self.with_expression(ctx, &struct_getter.source),
|
||||||
attribute: struct_getter.attribute.clone(),
|
attribute: struct_getter.attribute.clone(),
|
||||||
type_: process_type(ctx, &struct_getter.type_),
|
type_: struct_getter.type_.clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ast::Subexpression::Block(block) => {
|
ast::Subexpression::Block(block) => {
|
||||||
ast::Subexpression::Block(self.with_block(ctx, &block))
|
let (result, substitution) = self.with_block(ctx, &block);
|
||||||
|
substitution = compose_substitutions(substitution, unify(expression.type_, block.type_));
|
||||||
|
ast::Subexpression::Block(result)
|
||||||
},
|
},
|
||||||
ast::Subexpression::Op(op) => {
|
ast::Subexpression::Op(op) => {
|
||||||
|
let expr_left, subst_left = self.with_expression(ctx, &op.left);
|
||||||
|
let expr_right, subst_right = self.with_expression(ctx, &op.right);
|
||||||
|
substitution = compose_substitutions(substitution, subst_left);
|
||||||
|
substitution = compose_substitutions(substitution, subst_right);
|
||||||
|
substitution = compose_substitutions(substitution, unify(expression.type_, expr_left.type_));
|
||||||
|
substitution = compose_substitutions(substitution, unify(expression.type_, expr_right.type_));
|
||||||
ast::Subexpression::Op(ast::Operation{
|
ast::Subexpression::Op(ast::Operation{
|
||||||
left: self.with_expression(ctx, &op.left),
|
left: expr_left,
|
||||||
op: op.op.clone(),
|
op: op.op.clone(),
|
||||||
right: self.with_expression(ctx, &op.right),
|
right: expr_right,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
type_: process_type(ctx, &expression.type_),
|
type_: expression.type_.clone(),
|
||||||
}
|
};
|
||||||
|
return (expr, substitution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user