From 15d7e450cafd6170b5a9ca2a0095508e9c199036 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 17 Jan 2024 13:34:51 +0100 Subject: [PATCH 1/9] initial arrays --- crates/concrete_ast/src/expressions.rs | 10 +- crates/concrete_ast/src/types.rs | 25 ++ crates/concrete_codegen_mlir/src/codegen.rs | 399 +++++++++++++++++--- crates/concrete_driver/src/lib.rs | 8 + crates/concrete_parser/src/grammar.lalrpop | 42 ++- crates/concrete_parser/src/tokens.rs | 2 +- examples/borrow.con | 17 + 7 files changed, 434 insertions(+), 69 deletions(-) create mode 100644 examples/borrow.con diff --git a/crates/concrete_ast/src/expressions.rs b/crates/concrete_ast/src/expressions.rs index 0abd876..7ce2361 100644 --- a/crates/concrete_ast/src/expressions.rs +++ b/crates/concrete_ast/src/expressions.rs @@ -2,7 +2,7 @@ use crate::{common::Ident, statements::Statement, types::TypeSpec}; #[derive(Clone, Debug, Eq, PartialEq)] pub enum Expression { - Simple(SimpleExpr), + Value(ValueExpr), FnCall(FnCallOp), Match(MatchExpr), If(IfExpr), @@ -10,15 +10,15 @@ pub enum Expression { BinaryOp(Box, BinaryOp, Box), } -// needed for match variants and array accesses #[derive(Clone, Debug, Eq, PartialEq)] -pub enum SimpleExpr { +pub enum ValueExpr { ConstBool(bool), ConstChar(char), ConstInt(u64), ConstFloat(()), ConstStr(String), Path(PathOp), + Deref(PathOp), } #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -83,14 +83,14 @@ pub struct IfExpr { #[derive(Clone, Debug, Eq, PartialEq)] pub struct MatchVariant { - pub case: SimpleExpr, + pub case: ValueExpr, pub block: Vec, } #[derive(Clone, Debug, Eq, PartialEq)] pub enum PathSegment { FieldAccess(Ident), - ArrayIndex(SimpleExpr), + ArrayIndex(ValueExpr), } #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/crates/concrete_ast/src/types.rs b/crates/concrete_ast/src/types.rs index 450f8ee..2ae7c87 100644 --- a/crates/concrete_ast/src/types.rs +++ b/crates/concrete_ast/src/types.rs @@ -1,15 +1,40 @@ use crate::common::{DocString, Ident, Span}; +#[derive(Clone, Debug, Eq, Hash, PartialEq, Copy)] +pub enum RefType { + Borrow, + MutBorrow, +} + #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum TypeSpec { Simple { name: Ident, + is_ref: Option, + span: Span, }, Generic { name: Ident, + is_ref: Option, type_params: Vec, span: Span, }, + Array { + of_type: Box, + size: Option, + is_ref: Option, + span: Span, + }, +} + +impl TypeSpec { + pub fn is_ref(&self) -> Option { + match self { + TypeSpec::Simple { is_ref, .. } => *is_ref, + TypeSpec::Generic { is_ref, .. } => *is_ref, + TypeSpec::Array { is_ref, .. } => *is_ref, + } + } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index a4f10bd..1a57a97 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1,9 +1,10 @@ -use std::{collections::HashMap, error::Error}; +use std::{char::MAX, collections::HashMap, error::Error}; use bumpalo::Bump; use concrete_ast::{ expressions::{ - ArithOp, BinaryOp, CmpOp, Expression, FnCallOp, IfExpr, LogicOp, PathOp, SimpleExpr, + ArithOp, BinaryOp, CmpOp, Expression, FnCallOp, IfExpr, LogicOp, PathOp, PathSegment, + ValueExpr, }, functions::FunctionDef, modules::{Module, ModuleDefItem}, @@ -15,10 +16,15 @@ use concrete_session::Session; use melior::{ dialect::{ arith::{self, CmpiPredicate}, - cf, func, memref, + cf, func, + llvm::{self, r#type::opaque_pointer, LoadStoreOptions}, + memref, }, ir::{ - attribute::{FlatSymbolRefAttribute, IntegerAttribute, StringAttribute, TypeAttribute}, + attribute::{ + DenseI64ArrayAttribute, FlatSymbolRefAttribute, IntegerAttribute, StringAttribute, + TypeAttribute, + }, r#type::{FunctionType, IntegerType, MemRefType}, Block, BlockRef, Location, Module as MeliorModule, Operation, Region, Type, Value, ValueLike, @@ -144,26 +150,84 @@ impl<'ctx, 'parent> ScopeContext<'ctx, 'parent> { &self, context: &'ctx MeliorContext, spec: &TypeSpec, + ) -> Result, Box> { + match spec.is_ref() { + Some(_) => Ok(llvm::r#type::opaque_pointer(context)), + None => self.resolve_type_spec_ref(context, spec), + } + } + + /// Resolves the type this ref points to. + fn resolve_type_spec_ref( + &self, + context: &'ctx MeliorContext, + spec: &TypeSpec, ) -> Result, Box> { Ok(match spec { - TypeSpec::Simple { name } => self.resolve_type(context, &name.name)?, + TypeSpec::Simple { name, .. } => self.resolve_type(context, &name.name)?, TypeSpec::Generic { name, .. } => self.resolve_type(context, &name.name)?, + TypeSpec::Array { + of_type, + span, + is_ref, + size, + } => match size { + Some(size) => { + let inner_type = self.resolve_type_spec(context, of_type)?; + MemRefType::new(inner_type, &[*size], None, None).into() + /* + llvm::r#type::array( + self.resolve_type_spec(context, &of_type)?, + (*size).try_into().expect("size was above u32"), + ) + */ + } + None => { + // + let inner_type = self.resolve_type_spec(context, of_type)?; + Type::parse(context, &format!("memref")).unwrap() + // MemRefType::new(inner_type, &[(u32::MAX) as u64], None, None).into() + /* + llvm::r#type::r#struct( + context, + &[ + llvm::r#type::opaque_pointer(context), + IntegerType::new(context, 64).into(), + IntegerType::new(context, 64).into(), + ], + false, + ) + */ + } + }, }) } fn is_type_signed(&self, type_info: &TypeSpec) -> bool { let signed = ["i8", "i16", "i32", "i64", "i128"]; match type_info { - TypeSpec::Simple { name } => signed.contains(&name.name.as_str()), - TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Simple { name, is_ref, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Generic { name, is_ref, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Array { + of_type, + span, + is_ref, + size, + } => unreachable!(), } } fn is_float(&self, type_info: &TypeSpec) -> bool { let signed = ["f32", "f64"]; match type_info { - TypeSpec::Simple { name } => signed.contains(&name.name.as_str()), - TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Simple { name, is_ref, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Generic { name, is_ref, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Array { + of_type, + span, + is_ref, + size, + } => unreachable!(), } } } @@ -635,39 +699,9 @@ fn compile_expression<'ctx, 'parent: 'ctx>( ) -> Result, Box> { let location = Location::unknown(context); match info { - Expression::Simple(simple) => match simple { - SimpleExpr::ConstBool(value) => { - let value = - IntegerAttribute::new((*value).into(), IntegerType::new(context, 1).into()); - Ok(block - .append_operation(arith::constant(context, value.into(), location)) - .result(0)? - .into()) - } - SimpleExpr::ConstChar(value) => { - let value = - IntegerAttribute::new((*value) as i64, IntegerType::new(context, 32).into()); - Ok(block - .append_operation(arith::constant(context, value.into(), location)) - .result(0)? - .into()) - } - SimpleExpr::ConstInt(value) => { - let int_type = if let Some(type_info) = type_info { - scope_ctx.resolve_type_spec(context, type_info)? - } else { - IntegerType::new(context, 64).into() - }; - let value = IntegerAttribute::new((*value) as i64, int_type); - Ok(block - .append_operation(arith::constant(context, value.into(), location)) - .result(0)? - .into()) - } - SimpleExpr::ConstFloat(_) => todo!(), - SimpleExpr::ConstStr(_) => todo!(), - SimpleExpr::Path(value) => compile_path_op(session, context, scope_ctx, block, value), - }, + Expression::Value(value) => compile_value_expr( + session, context, scope_ctx, _helper, block, value, type_info, + ), Expression::FnCall(value) => { compile_fn_call(session, context, scope_ctx, _helper, block, value) } @@ -798,6 +832,55 @@ fn compile_expression<'ctx, 'parent: 'ctx>( } } +fn compile_value_expr<'ctx, 'parent: 'ctx>( + session: &Session, + context: &'ctx MeliorContext, + scope_ctx: &mut ScopeContext<'ctx, 'parent>, + _helper: &BlockHelper<'ctx, 'parent>, + block: &'parent Block<'ctx>, + value: &ValueExpr, + type_info: Option<&TypeSpec>, +) -> Result, Box> { + let location = Location::unknown(context); + match value { + ValueExpr::ConstBool(value) => { + let value = IntegerAttribute::new((*value).into(), IntegerType::new(context, 1).into()); + Ok(block + .append_operation(arith::constant(context, value.into(), location)) + .result(0)? + .into()) + } + ValueExpr::ConstChar(value) => { + let value = + IntegerAttribute::new((*value) as i64, IntegerType::new(context, 32).into()); + Ok(block + .append_operation(arith::constant(context, value.into(), location)) + .result(0)? + .into()) + } + ValueExpr::ConstInt(value) => { + let int_type = if let Some(type_info) = type_info { + scope_ctx.resolve_type_spec(context, type_info)? + } else { + IntegerType::new(context, 64).into() + }; + let value = IntegerAttribute::new((*value) as i64, int_type); + Ok(block + .append_operation(arith::constant(context, value.into(), location)) + .result(0)? + .into()) + } + ValueExpr::ConstFloat(_) => todo!(), + ValueExpr::ConstStr(_) => todo!(), + ValueExpr::Path(value) => { + compile_path_op(session, context, scope_ctx, _helper, block, value) + } + ValueExpr::Deref(value) => { + compile_deref(session, context, scope_ctx, _helper, block, value) + } + } +} + fn compile_fn_call<'ctx, 'parent: 'ctx>( session: &Session, context: &'ctx MeliorContext, @@ -857,20 +940,22 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( session: &Session, context: &'ctx MeliorContext, scope_ctx: &mut ScopeContext<'ctx, 'parent>, + helper: &BlockHelper<'ctx, 'parent>, block: &'parent Block<'ctx>, path: &PathOp, ) -> Result, Box> { - // For now only simple variables work. + // For now only simple and array variables work. // TODO: implement properly, this requires having structs implemented. let local = scope_ctx .locals .get(&path.first.name) - .expect("local not found"); + .expect("local not found") + .clone(); let location = get_location(context, session, path.first.span.from); - if local.alloca { + let mut value = if local.alloca { let k0 = block .append_operation(arith::constant( context, @@ -879,12 +964,228 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( )) .result(0)? .into(); - let value = block + block .append_operation(memref::load(local.value, &[k0], location)) .result(0)? - .into(); - Ok(value) + .into() } else { - Ok(local.value) + local.value + }; + + for segment in &path.extra { + match segment { + PathSegment::FieldAccess(_) => todo!(), + PathSegment::ArrayIndex(index) => { + let index = + compile_value_expr(session, context, scope_ctx, helper, block, index, None)?; + let index_ty = Type::index(context); + let index = block + .append_operation(melior::dialect::index::castu(index, index_ty, location)) + .result(0)? + .into(); + + if let TypeSpec::Array { + of_type, + size, + is_ref: _, + span, + } = &local.type_spec + { + let location = get_location(context, session, span.from); + let inner_type = scope_ctx.resolve_type_spec(context, of_type)?; + #[allow(clippy::if_same_then_else)] + if size.is_some() { + value = block + .append_operation(memref::load(value, &[index], location)) + .result(0)? + .into(); + /* + // its a llvm.array + let ptr = block + .append_operation(llvm::get_element_ptr_dynamic( + context, + value, + &[index], + inner_type, + opaque_pointer(context), + location, + )) + .result(0)? + .into(); + + value = block + .append_operation(llvm::load( + context, + ptr, + inner_type, + location, + LoadStoreOptions::new(), + )) + .result(0)? + .into(); + */ + } else { + value = block + .append_operation(memref::load(value, &[index], location)) + .result(0)? + .into(); + // its a struct {ptr,u64,u64} + /* + let ptr = block + .append_operation(llvm::extract_value( + context, + value, + DenseI64ArrayAttribute::new(context, &[0]), + opaque_pointer(context), + location, + )) + .result(0)? + .into(); + + let elem_ptr = block + .append_operation(llvm::get_element_ptr_dynamic( + context, + ptr, + &[index], + inner_type, + opaque_pointer(context), + location, + )) + .result(0)? + .into(); + + value = block + .append_operation(llvm::load( + context, + elem_ptr, + inner_type, + location, + LoadStoreOptions::new(), + )) + .result(0)? + .into(); + */ + } + } else { + panic!("type should be a array when indexing a value"); + } + } + } } + + Ok(value) +} + +fn compile_deref<'ctx, 'parent: 'ctx>( + session: &Session, + context: &'ctx MeliorContext, + scope_ctx: &mut ScopeContext<'ctx, 'parent>, + helper: &BlockHelper<'ctx, 'parent>, + block: &'parent Block<'ctx>, + path: &PathOp, +) -> Result, Box> { + let local = scope_ctx + .locals + .get(&path.first.name) + .expect("local not found") + .clone(); + + let location = get_location(context, session, path.first.span.from); + let inner_type = scope_ctx.resolve_type_spec_ref(context, &local.type_spec)?; + + let mut value = block + .append_operation(llvm::load( + context, + local.value, + inner_type, + location, + LoadStoreOptions::new(), + )) + .result(0)? + .into(); + + for segment in &path.extra { + match segment { + PathSegment::FieldAccess(_) => todo!(), + PathSegment::ArrayIndex(index) => { + let index = + compile_value_expr(session, context, scope_ctx, helper, block, index, None)?; + + if let TypeSpec::Array { + of_type, + size, + is_ref: _, + span, + } = &local.type_spec + { + let location = get_location(context, session, span.from); + let inner_type = scope_ctx.resolve_type_spec(context, of_type)?; + if size.is_some() { + // its a llvm.array + let ptr = block + .append_operation(llvm::get_element_ptr_dynamic( + context, + value, + &[index], + inner_type, + opaque_pointer(context), + location, + )) + .result(0)? + .into(); + + value = block + .append_operation(llvm::load( + context, + ptr, + inner_type, + location, + LoadStoreOptions::new(), + )) + .result(0)? + .into(); + } else { + // its a struct {ptr,u64,u64} + let ptr = block + .append_operation(llvm::extract_value( + context, + value, + DenseI64ArrayAttribute::new(context, &[0]), + opaque_pointer(context), + location, + )) + .result(0)? + .into(); + + let elem_ptr = block + .append_operation(llvm::get_element_ptr_dynamic( + context, + ptr, + &[index], + inner_type, + opaque_pointer(context), + location, + )) + .result(0)? + .into(); + + value = block + .append_operation(llvm::load( + context, + elem_ptr, + inner_type, + location, + LoadStoreOptions::new(), + )) + .result(0)? + .into(); + } + } else { + panic!("type should be a array when indexing a value"); + } + } + } + } + + Ok(value) } diff --git a/crates/concrete_driver/src/lib.rs b/crates/concrete_driver/src/lib.rs index 8c4735d..e293af0 100644 --- a/crates/concrete_driver/src/lib.rs +++ b/crates/concrete_driver/src/lib.rs @@ -23,6 +23,10 @@ pub struct CompilerArgs { /// Build as a library. #[arg(short, long, default_value_t = false)] library: bool, + + /// Prints the ast. + #[arg(long, default_value_t = false)] + print_ast: bool, } pub fn main() -> Result<(), Box> { @@ -53,6 +57,10 @@ pub fn main() -> Result<(), Box> { } }; + if args.print_ast { + println!("{:#?}", program); + } + let cwd = std::env::current_dir()?; // todo: find a better name, "target" would clash with rust if running in the source tree. let target_dir = cwd.join("build_artifacts/"); diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index d8b1cbe..2aac08e 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -66,7 +66,7 @@ extern { "!" => Token::OperatorNot, "~" => Token::OperatorBitwiseNot, "^" => Token::OperatorBitwiseXor, - "&" => Token::OperatorBitwiseAnd, + "&" => Token::Ampersand, "|" => Token::OperatorBitwiseOr, } } @@ -131,13 +131,27 @@ pub(crate) Ident: ast::common::Ident = { } } +pub(crate) RefType: ast::types::RefType = { + "&" => ast::types::RefType::Borrow, + "&" "mut" => ast::types::RefType::MutBorrow, +} + pub(crate) TypeSpec: ast::types::TypeSpec = { - => ast::types::TypeSpec::Simple { - name + => ast::types::TypeSpec::Simple { + name, + is_ref, + span: Span::new(lo, hi), }, - "<" > ">" => ast::types::TypeSpec::Generic { + "<" > ">" => ast::types::TypeSpec::Generic { name, type_params, + is_ref, + span: Span::new(lo, hi), + }, + "[" )?> "]" => ast::types::TypeSpec::Array { + of_type: Box::new(of_type), + size, + is_ref, span: Span::new(lo, hi), } } @@ -272,7 +286,7 @@ pub(crate) FunctionDef: ast::functions::FunctionDef = { // Expressions pub(crate) Term: ast::expressions::Expression = { - => ast::expressions::Expression::Simple(<>), + => ast::expressions::Expression::Value(<>), => ast::expressions::Expression::FnCall(<>), => ast::expressions::Expression::Match(<>), => ast::expressions::Expression::If(<>), @@ -339,14 +353,14 @@ pub UnaryOp: ast::expressions::UnaryOp = { "~" => ast::expressions::UnaryOp::BitwiseNot, } -pub(crate) SimpleExpr: ast::expressions::SimpleExpr = { - <"integer"> => ast::expressions::SimpleExpr::ConstInt(<>), - <"boolean"> => ast::expressions::SimpleExpr::ConstBool(<>), - <"string"> => ast::expressions::SimpleExpr::ConstStr(<>), - => ast::expressions::SimpleExpr::Path(<>), +pub(crate) ValueExpr: ast::expressions::ValueExpr = { + <"integer"> => ast::expressions::ValueExpr::ConstInt(<>), + <"boolean"> => ast::expressions::ValueExpr::ConstBool(<>), + <"string"> => ast::expressions::ValueExpr::ConstStr(<>), + => ast::expressions::ValueExpr::Path(<>), + "*" => ast::expressions::ValueExpr::Deref(<>), } - pub(crate) IfExpr: ast::expressions::IfExpr = { "if" "{" "}" "}")?> => { @@ -369,14 +383,14 @@ pub(crate) MatchExpr: ast::expressions::MatchExpr = { pub(crate) MatchVariant: ast::expressions::MatchVariant = { // 0 -> 1 - "->" => { + "->" => { ast::expressions::MatchVariant { case, block: vec![stmt] } }, // x -> { ... } - "->" "{" "}" => { + "->" "{" "}" => { ast::expressions::MatchVariant { case, block: stmts @@ -393,7 +407,7 @@ pub(crate) PathOp: ast::expressions::PathOp = { pub(crate) PathSegment: ast::expressions::PathSegment = { "." => ast::expressions::PathSegment::FieldAccess(<>), - "[" "]" => ast::expressions::PathSegment::ArrayIndex(e), + "[" "]" => ast::expressions::PathSegment::ArrayIndex(e), } pub PathSegments: Vec = { diff --git a/crates/concrete_parser/src/tokens.rs b/crates/concrete_parser/src/tokens.rs index 9e06b3f..316a74d 100644 --- a/crates/concrete_parser/src/tokens.rs +++ b/crates/concrete_parser/src/tokens.rs @@ -122,7 +122,7 @@ pub enum Token { #[token("^")] OperatorBitwiseXor, #[token("&")] - OperatorBitwiseAnd, + Ampersand, #[token("|")] OperatorBitwiseOr, } diff --git a/examples/borrow.con b/examples/borrow.con new file mode 100644 index 0000000..dd56175 --- /dev/null +++ b/examples/borrow.con @@ -0,0 +1,17 @@ +mod Simple { + fn main(argc: i64) -> i64 { + return argc; + } + + fn hello(a: &i64) -> i64 { + return *a; + } + + fn hello2(a: [i64]) -> i64 { + return a[0]; + } + + fn hello3(a: [i64; 4]) -> i64 { + return a[0]; + } +} From a490339bc2d771164731ecbb13070b99b3a6232c Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 17 Jan 2024 16:17:10 +0100 Subject: [PATCH 2/9] wip --- crates/concrete_codegen_mlir/src/codegen.rs | 263 ++++++++------------ examples/borrow.con | 10 +- 2 files changed, 106 insertions(+), 167 deletions(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 1a57a97..26ff84f 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -25,9 +25,10 @@ use melior::{ DenseI64ArrayAttribute, FlatSymbolRefAttribute, IntegerAttribute, StringAttribute, TypeAttribute, }, + operation::OperationBuilder, r#type::{FunctionType, IntegerType, MemRefType}, - Block, BlockRef, Location, Module as MeliorModule, Operation, Region, Type, Value, - ValueLike, + Block, BlockRef, Location, Module as MeliorModule, Operation, Region, Type, TypeLike, + Value, ValueLike, }, Context as MeliorContext, }; @@ -152,7 +153,12 @@ impl<'ctx, 'parent> ScopeContext<'ctx, 'parent> { spec: &TypeSpec, ) -> Result, Box> { match spec.is_ref() { - Some(_) => Ok(llvm::r#type::opaque_pointer(context)), + Some(_) => { + Ok( + MemRefType::new(self.resolve_type_spec_ref(context, spec)?, &[], None, None) + .into(), + ) + } None => self.resolve_type_spec_ref(context, spec), } } @@ -168,8 +174,8 @@ impl<'ctx, 'parent> ScopeContext<'ctx, 'parent> { TypeSpec::Generic { name, .. } => self.resolve_type(context, &name.name)?, TypeSpec::Array { of_type, - span, - is_ref, + span: _, + is_ref: _, size, } => match size { Some(size) => { @@ -185,19 +191,16 @@ impl<'ctx, 'parent> ScopeContext<'ctx, 'parent> { None => { // let inner_type = self.resolve_type_spec(context, of_type)?; - Type::parse(context, &format!("memref")).unwrap() - // MemRefType::new(inner_type, &[(u32::MAX) as u64], None, None).into() - /* + // Type::parse(context, &format!("memref")).unwrap() + llvm::r#type::r#struct( context, &[ - llvm::r#type::opaque_pointer(context), - IntegerType::new(context, 64).into(), + Type::parse(context, &format!("memref")).unwrap(), IntegerType::new(context, 64).into(), ], false, ) - */ } }, }) @@ -562,6 +565,17 @@ fn compile_while<'c, 'this: 'c>( Ok(merge_block) } +fn is_local_copy(a: &Expression) -> Option<(&PathOp, bool)> { + match a { + Expression::Value(value) => match value { + ValueExpr::Path(path) => Some((path, false)), + ValueExpr::Deref(path) => Some((path, true)), + _ => None, + }, + _ => None, + } +} + fn compile_let_stmt<'ctx, 'parent: 'ctx>( session: &Session, context: &'ctx MeliorContext, @@ -572,6 +586,8 @@ fn compile_let_stmt<'ctx, 'parent: 'ctx>( ) -> Result<(), Box> { match &info.target { LetStmtTarget::Simple { name, r#type } => { + let location = get_location(context, session, name.span.from); + let value = compile_expression( session, context, @@ -581,10 +597,7 @@ fn compile_let_stmt<'ctx, 'parent: 'ctx>( &info.value, Some(r#type), )?; - - let location = get_location(context, session, name.span.from); - - let memref_type = MemRefType::new(value.r#type(), &[1], None, None); + let memref_type = MemRefType::new(value.r#type(), &[], None, None); let alloca: Value = block .append_operation(memref::alloca( @@ -605,6 +618,7 @@ fn compile_let_stmt<'ctx, 'parent: 'ctx>( )) .result(0)? .into(); + block.append_operation(memref::store(value, alloca, &[k0], location)); scope_ctx @@ -647,15 +661,67 @@ fn compile_assign_stmt<'ctx, 'parent: 'ctx>( Some(&local.type_spec), )?; - let k0 = block - .append_operation(arith::constant( - context, - IntegerAttribute::new(0, Type::index(context)).into(), - location, - )) - .result(0)? - .into(); - block.append_operation(memref::store(value, local.value, &[k0], location)); + if info.target.extra.is_empty() { + block.append_operation(memref::store(value, local.value, &[], location)); + } else { + let mut store_target = block + .append_operation(memref::load(local.value, &[], location)) + .result(0)? + .into(); + + let mut segment_iter = info.target.extra.iter().peekable(); + + while let Some(segment) = segment_iter.next() { + match segment { + PathSegment::FieldAccess(_) => todo!(), + PathSegment::ArrayIndex(index) => { + let index = compile_value_expr( + session, context, scope_ctx, helper, block, index, None, + )?; + let index_ty = Type::index(context); + let index = block + .append_operation(melior::dialect::index::castu(index, index_ty, location)) + .result(0)? + .into(); + + if let TypeSpec::Array { + of_type: _, + size, + is_ref: _, + span, + } = &local.type_spec + { + let location = get_location(context, session, span.from); + + #[allow(clippy::if_same_then_else)] + if size.is_some() { + // todo: check inbounds? + store_target = block + .append_operation(memref::load(store_target, &[index], location)) + .result(0)? + .into(); + } else { + store_target = block + .append_operation(memref::load(store_target, &[index], location)) + .result(0)? + .into(); + } + + if segment_iter.peek().is_none() { + block.append_operation(memref::store( + value, + store_target, + &[index], + location, + )); + } + } else { + panic!("type should be a array when indexing a value"); + } + } + } + } + } Ok(()) } @@ -956,16 +1022,8 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( let location = get_location(context, session, path.first.span.from); let mut value = if local.alloca { - let k0 = block - .append_operation(arith::constant( - context, - IntegerAttribute::new(0, Type::index(context)).into(), - location, - )) - .result(0)? - .into(); block - .append_operation(memref::load(local.value, &[k0], location)) + .append_operation(memref::load(local.value, &[], location)) .result(0)? .into() } else { @@ -985,86 +1043,25 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( .into(); if let TypeSpec::Array { - of_type, + of_type: _, size, is_ref: _, span, } = &local.type_spec { let location = get_location(context, session, span.from); - let inner_type = scope_ctx.resolve_type_spec(context, of_type)?; #[allow(clippy::if_same_then_else)] if size.is_some() { + // todo: check inbounds? value = block .append_operation(memref::load(value, &[index], location)) .result(0)? .into(); - /* - // its a llvm.array - let ptr = block - .append_operation(llvm::get_element_ptr_dynamic( - context, - value, - &[index], - inner_type, - opaque_pointer(context), - location, - )) - .result(0)? - .into(); - - value = block - .append_operation(llvm::load( - context, - ptr, - inner_type, - location, - LoadStoreOptions::new(), - )) - .result(0)? - .into(); - */ } else { value = block .append_operation(memref::load(value, &[index], location)) .result(0)? .into(); - // its a struct {ptr,u64,u64} - /* - let ptr = block - .append_operation(llvm::extract_value( - context, - value, - DenseI64ArrayAttribute::new(context, &[0]), - opaque_pointer(context), - location, - )) - .result(0)? - .into(); - - let elem_ptr = block - .append_operation(llvm::get_element_ptr_dynamic( - context, - ptr, - &[index], - inner_type, - opaque_pointer(context), - location, - )) - .result(0)? - .into(); - - value = block - .append_operation(llvm::load( - context, - elem_ptr, - inner_type, - location, - LoadStoreOptions::new(), - )) - .result(0)? - .into(); - */ } } else { panic!("type should be a array when indexing a value"); @@ -1094,15 +1091,8 @@ fn compile_deref<'ctx, 'parent: 'ctx>( let inner_type = scope_ctx.resolve_type_spec_ref(context, &local.type_spec)?; let mut value = block - .append_operation(llvm::load( - context, - local.value, - inner_type, - location, - LoadStoreOptions::new(), - )) - .result(0)? - .into(); + .append_operation(memref::load(local.value, &[], location)).result(0)?.into(); + for segment in &path.extra { match segment { @@ -1110,73 +1100,30 @@ fn compile_deref<'ctx, 'parent: 'ctx>( PathSegment::ArrayIndex(index) => { let index = compile_value_expr(session, context, scope_ctx, helper, block, index, None)?; + let index_ty = Type::index(context); + let index = block + .append_operation(melior::dialect::index::castu(index, index_ty, location)) + .result(0)? + .into(); if let TypeSpec::Array { - of_type, + of_type: _, size, is_ref: _, span, } = &local.type_spec { let location = get_location(context, session, span.from); - let inner_type = scope_ctx.resolve_type_spec(context, of_type)?; + #[allow(clippy::if_same_then_else)] if size.is_some() { - // its a llvm.array - let ptr = block - .append_operation(llvm::get_element_ptr_dynamic( - context, - value, - &[index], - inner_type, - opaque_pointer(context), - location, - )) - .result(0)? - .into(); - + // todo: check inbounds? value = block - .append_operation(llvm::load( - context, - ptr, - inner_type, - location, - LoadStoreOptions::new(), - )) + .append_operation(memref::load(value, &[index], location)) .result(0)? .into(); } else { - // its a struct {ptr,u64,u64} - let ptr = block - .append_operation(llvm::extract_value( - context, - value, - DenseI64ArrayAttribute::new(context, &[0]), - opaque_pointer(context), - location, - )) - .result(0)? - .into(); - - let elem_ptr = block - .append_operation(llvm::get_element_ptr_dynamic( - context, - ptr, - &[index], - inner_type, - opaque_pointer(context), - location, - )) - .result(0)? - .into(); - value = block - .append_operation(llvm::load( - context, - elem_ptr, - inner_type, - location, - LoadStoreOptions::new(), - )) + .append_operation(memref::load(value, &[index], location)) .result(0)? .into(); } diff --git a/examples/borrow.con b/examples/borrow.con index dd56175..b6dfca8 100644 --- a/examples/borrow.con +++ b/examples/borrow.con @@ -3,15 +3,7 @@ mod Simple { return argc; } - fn hello(a: &i64) -> i64 { + fn dereference(a: &i64) -> i64 { return *a; } - - fn hello2(a: [i64]) -> i64 { - return a[0]; - } - - fn hello3(a: [i64; 4]) -> i64 { - return a[0]; - } } From 37a040cd2879243994202d1134c0e9518f4a802c Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Wed, 17 Jan 2024 16:42:56 +0100 Subject: [PATCH 3/9] references --- crates/concrete_ast/src/expressions.rs | 7 +- crates/concrete_codegen_mlir/src/codegen.rs | 219 +++++--------------- crates/concrete_driver/tests/programs.rs | 28 +++ crates/concrete_parser/src/grammar.lalrpop | 4 + examples/borrow.con | 9 +- 5 files changed, 102 insertions(+), 165 deletions(-) diff --git a/crates/concrete_ast/src/expressions.rs b/crates/concrete_ast/src/expressions.rs index 7ce2361..12f8752 100644 --- a/crates/concrete_ast/src/expressions.rs +++ b/crates/concrete_ast/src/expressions.rs @@ -1,4 +1,8 @@ -use crate::{common::Ident, statements::Statement, types::TypeSpec}; +use crate::{ + common::Ident, + statements::Statement, + types::{RefType, TypeSpec}, +}; #[derive(Clone, Debug, Eq, PartialEq)] pub enum Expression { @@ -19,6 +23,7 @@ pub enum ValueExpr { ConstStr(String), Path(PathOp), Deref(PathOp), + AsRef { path: PathOp, ref_type: RefType }, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 26ff84f..b4bf8bd 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -1,4 +1,4 @@ -use std::{char::MAX, collections::HashMap, error::Error}; +use std::{collections::HashMap, error::Error}; use bumpalo::Bump; use concrete_ast::{ @@ -16,19 +16,13 @@ use concrete_session::Session; use melior::{ dialect::{ arith::{self, CmpiPredicate}, - cf, func, - llvm::{self, r#type::opaque_pointer, LoadStoreOptions}, - memref, + cf, func, memref, }, ir::{ - attribute::{ - DenseI64ArrayAttribute, FlatSymbolRefAttribute, IntegerAttribute, StringAttribute, - TypeAttribute, - }, - operation::OperationBuilder, + attribute::{FlatSymbolRefAttribute, IntegerAttribute, StringAttribute, TypeAttribute}, r#type::{FunctionType, IntegerType, MemRefType}, - Block, BlockRef, Location, Module as MeliorModule, Operation, Region, Type, TypeLike, - Value, ValueLike, + Block, BlockRef, Location, Module as MeliorModule, Operation, Region, Type, Value, + ValueLike, }, Context as MeliorContext, }; @@ -172,65 +166,27 @@ impl<'ctx, 'parent> ScopeContext<'ctx, 'parent> { Ok(match spec { TypeSpec::Simple { name, .. } => self.resolve_type(context, &name.name)?, TypeSpec::Generic { name, .. } => self.resolve_type(context, &name.name)?, - TypeSpec::Array { - of_type, - span: _, - is_ref: _, - size, - } => match size { - Some(size) => { - let inner_type = self.resolve_type_spec(context, of_type)?; - MemRefType::new(inner_type, &[*size], None, None).into() - /* - llvm::r#type::array( - self.resolve_type_spec(context, &of_type)?, - (*size).try_into().expect("size was above u32"), - ) - */ - } - None => { - // - let inner_type = self.resolve_type_spec(context, of_type)?; - // Type::parse(context, &format!("memref")).unwrap() - - llvm::r#type::r#struct( - context, - &[ - Type::parse(context, &format!("memref")).unwrap(), - IntegerType::new(context, 64).into(), - ], - false, - ) - } - }, + TypeSpec::Array { .. } => { + todo!("implement arrays") + } }) } fn is_type_signed(&self, type_info: &TypeSpec) -> bool { let signed = ["i8", "i16", "i32", "i64", "i128"]; match type_info { - TypeSpec::Simple { name, is_ref, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Generic { name, is_ref, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Array { - of_type, - span, - is_ref, - size, - } => unreachable!(), + TypeSpec::Simple { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Array { .. } => unreachable!(), } } fn is_float(&self, type_info: &TypeSpec) -> bool { let signed = ["f32", "f64"]; match type_info { - TypeSpec::Simple { name, is_ref, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Generic { name, is_ref, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Array { - of_type, - span, - is_ref, - size, - } => unreachable!(), + TypeSpec::Simple { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Array { .. } => unreachable!(), } } } @@ -565,17 +521,6 @@ fn compile_while<'c, 'this: 'c>( Ok(merge_block) } -fn is_local_copy(a: &Expression) -> Option<(&PathOp, bool)> { - match a { - Expression::Value(value) => match value { - ValueExpr::Path(path) => Some((path, false)), - ValueExpr::Deref(path) => Some((path, true)), - _ => None, - }, - _ => None, - } -} - fn compile_let_stmt<'ctx, 'parent: 'ctx>( session: &Session, context: &'ctx MeliorContext, @@ -610,16 +555,8 @@ fn compile_let_stmt<'ctx, 'parent: 'ctx>( )) .result(0)? .into(); - let k0 = block - .append_operation(arith::constant( - context, - IntegerAttribute::new(0, Type::index(context)).into(), - location, - )) - .result(0)? - .into(); - block.append_operation(memref::store(value, alloca, &[k0], location)); + block.append_operation(memref::store(value, alloca, &[], location)); scope_ctx .locals @@ -907,6 +844,7 @@ fn compile_value_expr<'ctx, 'parent: 'ctx>( value: &ValueExpr, type_info: Option<&TypeSpec>, ) -> Result, Box> { + tracing::debug!("compiling value_expr for {:?}", value); let location = Location::unknown(context); match value { ValueExpr::ConstBool(value) => { @@ -944,6 +882,9 @@ fn compile_value_expr<'ctx, 'parent: 'ctx>( ValueExpr::Deref(value) => { compile_deref(session, context, scope_ctx, _helper, block, value) } + ValueExpr::AsRef { path, ref_type: _ } => { + compile_asref(session, context, scope_ctx, _helper, block, path) + } } } @@ -955,6 +896,7 @@ fn compile_fn_call<'ctx, 'parent: 'ctx>( block: &'parent Block<'ctx>, info: &FnCallOp, ) -> Result, Box> { + tracing::debug!("compiling fncall: {:?}", info); let mut args = Vec::with_capacity(info.args.len()); let location = get_location(context, session, info.target.span.from); @@ -1006,10 +948,11 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( session: &Session, context: &'ctx MeliorContext, scope_ctx: &mut ScopeContext<'ctx, 'parent>, - helper: &BlockHelper<'ctx, 'parent>, + _helper: &BlockHelper<'ctx, 'parent>, block: &'parent Block<'ctx>, path: &PathOp, ) -> Result, Box> { + tracing::debug!("compiling pathop {:?}", path); // For now only simple and array variables work. // TODO: implement properly, this requires having structs implemented. @@ -1021,7 +964,7 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( let location = get_location(context, session, path.first.span.from); - let mut value = if local.alloca { + let value = if local.alloca { block .append_operation(memref::load(local.value, &[], location)) .result(0)? @@ -1030,46 +973,6 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( local.value }; - for segment in &path.extra { - match segment { - PathSegment::FieldAccess(_) => todo!(), - PathSegment::ArrayIndex(index) => { - let index = - compile_value_expr(session, context, scope_ctx, helper, block, index, None)?; - let index_ty = Type::index(context); - let index = block - .append_operation(melior::dialect::index::castu(index, index_ty, location)) - .result(0)? - .into(); - - if let TypeSpec::Array { - of_type: _, - size, - is_ref: _, - span, - } = &local.type_spec - { - let location = get_location(context, session, span.from); - #[allow(clippy::if_same_then_else)] - if size.is_some() { - // todo: check inbounds? - value = block - .append_operation(memref::load(value, &[index], location)) - .result(0)? - .into(); - } else { - value = block - .append_operation(memref::load(value, &[index], location)) - .result(0)? - .into(); - } - } else { - panic!("type should be a array when indexing a value"); - } - } - } - } - Ok(value) } @@ -1077,10 +980,11 @@ fn compile_deref<'ctx, 'parent: 'ctx>( session: &Session, context: &'ctx MeliorContext, scope_ctx: &mut ScopeContext<'ctx, 'parent>, - helper: &BlockHelper<'ctx, 'parent>, + _helper: &BlockHelper<'ctx, 'parent>, block: &'parent Block<'ctx>, path: &PathOp, ) -> Result, Box> { + tracing::debug!("compiling deref for {:?}", path); let local = scope_ctx .locals .get(&path.first.name) @@ -1088,51 +992,40 @@ fn compile_deref<'ctx, 'parent: 'ctx>( .clone(); let location = get_location(context, session, path.first.span.from); - let inner_type = scope_ctx.resolve_type_spec_ref(context, &local.type_spec)?; let mut value = block - .append_operation(memref::load(local.value, &[], location)).result(0)?.into(); - - - for segment in &path.extra { - match segment { - PathSegment::FieldAccess(_) => todo!(), - PathSegment::ArrayIndex(index) => { - let index = - compile_value_expr(session, context, scope_ctx, helper, block, index, None)?; - let index_ty = Type::index(context); - let index = block - .append_operation(melior::dialect::index::castu(index, index_ty, location)) - .result(0)? - .into(); - - if let TypeSpec::Array { - of_type: _, - size, - is_ref: _, - span, - } = &local.type_spec - { - let location = get_location(context, session, span.from); - #[allow(clippy::if_same_then_else)] - if size.is_some() { - // todo: check inbounds? - value = block - .append_operation(memref::load(value, &[index], location)) - .result(0)? - .into(); - } else { - value = block - .append_operation(memref::load(value, &[index], location)) - .result(0)? - .into(); - } - } else { - panic!("type should be a array when indexing a value"); - } - } - } + .append_operation(memref::load(local.value, &[], location)) + .result(0)? + .into(); + + if local.alloca { + value = block + .append_operation(memref::load(value, &[], location)) + .result(0)? + .into(); } Ok(value) } + +fn compile_asref<'ctx, 'parent: 'ctx>( + _session: &Session, + _context: &'ctx MeliorContext, + scope_ctx: &mut ScopeContext<'ctx, 'parent>, + _helper: &BlockHelper<'ctx, 'parent>, + _block: &'parent Block<'ctx>, + path: &PathOp, +) -> Result, Box> { + tracing::debug!("compiling asref for {:?}", path); + let local = scope_ctx + .locals + .get(&path.first.name) + .expect("local not found") + .clone(); + + if !local.alloca { + panic!("can only take refs to non register values"); + } + + Ok(local.value) +} diff --git a/crates/concrete_driver/tests/programs.rs b/crates/concrete_driver/tests/programs.rs index 14cee5e..fecc2f3 100644 --- a/crates/concrete_driver/tests/programs.rs +++ b/crates/concrete_driver/tests/programs.rs @@ -130,3 +130,31 @@ fn test_import() { let code = output.status.code().unwrap(); assert_eq!(code, 8); } + +#[test] +fn test_reference() { + let source = r#" + mod Simple { + fn main(argc: i64) -> i64 { + let x: i64 = argc; + return references(x) + dereference(&x); + } + + fn dereference(a: &i64) -> i64 { + return *a; + } + + fn references(a: i64) -> i64 { + let x: i64 = a; + let y: &i64 = &x; + return *y; + } + } + "#; + + let result = compile_program(source, "references", false).expect("failed to compile"); + + let output = run_program(&result.binary_file).expect("failed to run"); + let code = output.status.code().unwrap(); + assert_eq!(code, 2); +} diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index 2aac08e..7bcda21 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -359,6 +359,10 @@ pub(crate) ValueExpr: ast::expressions::ValueExpr = { <"string"> => ast::expressions::ValueExpr::ConstStr(<>), => ast::expressions::ValueExpr::Path(<>), "*" => ast::expressions::ValueExpr::Deref(<>), + => ast::expressions::ValueExpr::AsRef { + path, + ref_type + }, } pub(crate) IfExpr: ast::expressions::IfExpr = { diff --git a/examples/borrow.con b/examples/borrow.con index b6dfca8..1f99c91 100644 --- a/examples/borrow.con +++ b/examples/borrow.con @@ -1,9 +1,16 @@ mod Simple { fn main(argc: i64) -> i64 { - return argc; + let x: i64 = argc; + return references(x) + dereference(&x); } fn dereference(a: &i64) -> i64 { return *a; } + + fn references(a: i64) -> i64 { + let x: i64 = a; + let y: &i64 = &x; + return *y; + } } From a08d91599d139b2faaa0673f5d55a8254cff60b0 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 18 Jan 2024 15:51:48 +0100 Subject: [PATCH 4/9] clean --- Cargo.lock | 4 +- crates/concrete_codegen_mlir/Cargo.toml | 2 +- crates/concrete_codegen_mlir/src/codegen.rs | 65 +-------------------- 3 files changed, 5 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4523aa7..25c2bd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -978,9 +978,9 @@ dependencies = [ [[package]] name = "melior" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758bbd4448db9e994578ab48a6da5210512378f70ac1632cc8c2ae0fbd6c21b5" +checksum = "878012ddccd6fdd099a4d98cebdecbaed9bc5eb325d0778ab9d4f4a52c67c18e" dependencies = [ "dashmap", "melior-macro", diff --git a/crates/concrete_codegen_mlir/Cargo.toml b/crates/concrete_codegen_mlir/Cargo.toml index 19ce13e..9df9c6f 100644 --- a/crates/concrete_codegen_mlir/Cargo.toml +++ b/crates/concrete_codegen_mlir/Cargo.toml @@ -11,7 +11,7 @@ concrete_ast = { path = "../concrete_ast"} concrete_session = { path = "../concrete_session"} itertools = "0.12.0" llvm-sys = "170.0.1" -melior = { version = "0.15.0", features = ["ods-dialects"] } +melior = { version = "0.15.2", features = ["ods-dialects"] } mlir-sys = "0.2.1" tracing.workspace = true diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index b4bf8bd..ce79401 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -3,8 +3,7 @@ use std::{collections::HashMap, error::Error}; use bumpalo::Bump; use concrete_ast::{ expressions::{ - ArithOp, BinaryOp, CmpOp, Expression, FnCallOp, IfExpr, LogicOp, PathOp, PathSegment, - ValueExpr, + ArithOp, BinaryOp, CmpOp, Expression, FnCallOp, IfExpr, LogicOp, PathOp, ValueExpr, }, functions::FunctionDef, modules::{Module, ModuleDefItem}, @@ -598,67 +597,7 @@ fn compile_assign_stmt<'ctx, 'parent: 'ctx>( Some(&local.type_spec), )?; - if info.target.extra.is_empty() { - block.append_operation(memref::store(value, local.value, &[], location)); - } else { - let mut store_target = block - .append_operation(memref::load(local.value, &[], location)) - .result(0)? - .into(); - - let mut segment_iter = info.target.extra.iter().peekable(); - - while let Some(segment) = segment_iter.next() { - match segment { - PathSegment::FieldAccess(_) => todo!(), - PathSegment::ArrayIndex(index) => { - let index = compile_value_expr( - session, context, scope_ctx, helper, block, index, None, - )?; - let index_ty = Type::index(context); - let index = block - .append_operation(melior::dialect::index::castu(index, index_ty, location)) - .result(0)? - .into(); - - if let TypeSpec::Array { - of_type: _, - size, - is_ref: _, - span, - } = &local.type_spec - { - let location = get_location(context, session, span.from); - - #[allow(clippy::if_same_then_else)] - if size.is_some() { - // todo: check inbounds? - store_target = block - .append_operation(memref::load(store_target, &[index], location)) - .result(0)? - .into(); - } else { - store_target = block - .append_operation(memref::load(store_target, &[index], location)) - .result(0)? - .into(); - } - - if segment_iter.peek().is_none() { - block.append_operation(memref::store( - value, - store_target, - &[index], - location, - )); - } - } else { - panic!("type should be a array when indexing a value"); - } - } - } - } - } + block.append_operation(memref::store(value, local.value, &[], location)); Ok(()) } From a7bc0199a67337bbc110da39e9cffe37afbd1f69 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 18 Jan 2024 15:57:09 +0100 Subject: [PATCH 5/9] better --- crates/concrete_codegen_mlir/src/codegen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index ce79401..0db203f 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -898,7 +898,7 @@ fn compile_path_op<'ctx, 'parent: 'ctx>( let local = scope_ctx .locals .get(&path.first.name) - .expect("local not found") + .unwrap_or_else(|| panic!("local {} not found", path.first.name)) .clone(); let location = get_location(context, session, path.first.span.from); From 843cdecbfb83d7596967f78faa8eeda9f81ba551 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 18 Jan 2024 17:33:14 +0100 Subject: [PATCH 6/9] check --- Cargo.lock | 16 ++- Cargo.toml | 2 +- crates/concrete_ast/src/common.rs | 8 ++ crates/concrete_ast/src/imports.rs | 3 +- crates/concrete_ast/src/modules.rs | 3 +- crates/concrete_check/Cargo.toml | 13 +++ crates/concrete_check/src/ast_helper.rs | 127 +++++++++++++++++++++ crates/concrete_check/src/lib.rs | 101 ++++++++++++++++ crates/concrete_driver/Cargo.toml | 1 + crates/concrete_driver/src/lib.rs | 12 ++ crates/concrete_parser/src/grammar.lalrpop | 8 +- crates/concrete_type_checker/Cargo.toml | 8 -- crates/concrete_type_checker/src/lib.rs | 1 - examples/missing_import.con | 8 ++ 14 files changed, 292 insertions(+), 19 deletions(-) create mode 100644 crates/concrete_check/Cargo.toml create mode 100644 crates/concrete_check/src/ast_helper.rs create mode 100644 crates/concrete_check/src/lib.rs delete mode 100644 crates/concrete_type_checker/Cargo.toml delete mode 100644 crates/concrete_type_checker/src/lib.rs create mode 100644 examples/missing_import.con diff --git a/Cargo.lock b/Cargo.lock index 25c2bd6..60fadbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,6 +357,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "concrete_check" +version = "0.1.0" +dependencies = [ + "ariadne", + "concrete_ast", + "concrete_session", + "itertools 0.12.0", + "thiserror", +] + [[package]] name = "concrete_codegen_mlir" version = "0.1.0" @@ -379,6 +390,7 @@ dependencies = [ "ariadne", "clap", "concrete_ast", + "concrete_check", "concrete_codegen_mlir", "concrete_parser", "concrete_session", @@ -409,10 +421,6 @@ dependencies = [ "ariadne", ] -[[package]] -name = "concrete_type_checker" -version = "0.1.0" - [[package]] name = "convert_case" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index d8e9029..27930ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] resolver = "2" -members = [ "crates/concrete","crates/concrete_ast", "crates/concrete_codegen_mlir", "crates/concrete_driver", "crates/concrete_parser", "crates/concrete_session", "crates/concrete_type_checker"] +members = [ "crates/concrete","crates/concrete_ast", "crates/concrete_codegen_mlir", "crates/concrete_driver", "crates/concrete_parser", "crates/concrete_session", "crates/concrete_check"] [profile.release] lto = true diff --git a/crates/concrete_ast/src/common.rs b/crates/concrete_ast/src/common.rs index c94d349..ef7a45f 100644 --- a/crates/concrete_ast/src/common.rs +++ b/crates/concrete_ast/src/common.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Span { pub from: usize, @@ -10,6 +12,12 @@ impl Span { } } +impl From for Range { + fn from(val: Span) -> Self { + val.from..val.to + } +} + #[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] pub struct DocString { contents: String, diff --git a/crates/concrete_ast/src/imports.rs b/crates/concrete_ast/src/imports.rs index f158b9b..615230c 100644 --- a/crates/concrete_ast/src/imports.rs +++ b/crates/concrete_ast/src/imports.rs @@ -1,7 +1,8 @@ -use crate::common::Ident; +use crate::common::{Ident, Span}; #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct ImportStmt { pub module: Vec, pub symbols: Vec, + pub span: Span, } diff --git a/crates/concrete_ast/src/modules.rs b/crates/concrete_ast/src/modules.rs index d67b590..5ed22cf 100644 --- a/crates/concrete_ast/src/modules.rs +++ b/crates/concrete_ast/src/modules.rs @@ -1,5 +1,5 @@ use crate::{ - common::{DocString, Ident}, + common::{DocString, Ident, Span}, constants::ConstantDef, functions::FunctionDef, imports::ImportStmt, @@ -13,6 +13,7 @@ pub struct Module { pub imports: Vec, pub name: Ident, pub contents: Vec, + pub span: Span, } #[derive(Clone, Debug, Eq, PartialEq)] diff --git a/crates/concrete_check/Cargo.toml b/crates/concrete_check/Cargo.toml new file mode 100644 index 0000000..b326b82 --- /dev/null +++ b/crates/concrete_check/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "concrete_check" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ariadne = { version = "0.4.0", features = ["auto-color"] } +concrete_ast = { version = "0.1.0", path = "../concrete_ast" } +concrete_session = { version = "0.1.0", path = "../concrete_session" } +itertools = "0.12.0" +thiserror = "1.0.56" diff --git a/crates/concrete_check/src/ast_helper.rs b/crates/concrete_check/src/ast_helper.rs new file mode 100644 index 0000000..0d8c6bd --- /dev/null +++ b/crates/concrete_check/src/ast_helper.rs @@ -0,0 +1,127 @@ +use std::collections::HashMap; + +use concrete_ast::{ + common::Ident, + constants::ConstantDef, + functions::FunctionDef, + modules::{Module, ModuleDefItem}, + structs::StructDecl, + types::TypeDecl, + Program, +}; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ModuleInfo<'p> { + pub name: String, + pub functions: HashMap, + pub constants: HashMap, + pub structs: HashMap, + pub types: HashMap, + pub modules: HashMap>, +} + +impl<'p> ModuleInfo<'p> { + pub fn get_module_from_import(&self, import: &[Ident]) -> Option<&ModuleInfo<'p>> { + let next = import.first()?; + let module = self.modules.get(&next.name)?; + + if import.len() > 1 { + module.get_module_from_import(&import[1..]) + } else { + Some(module) + } + } + + /// Returns the symbol name from a local name. + pub fn get_symbol_name(&self, local_name: &str) -> String { + if local_name == "main" { + return local_name.to_string(); + } + + let mut result = self.name.clone(); + + result.push_str("::"); + result.push_str(local_name); + + result + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AstHelper<'p> { + pub root: &'p Program, + pub modules: HashMap>, +} + +impl<'p> AstHelper<'p> { + pub fn new(root: &'p Program) -> Self { + let mut modules = HashMap::default(); + + for module in &root.modules { + modules.insert( + module.name.name.clone(), + Self::create_module_info(module, None), + ); + } + + Self { root, modules } + } + + pub fn get_module_from_import(&self, import: &[Ident]) -> Option<&ModuleInfo<'p>> { + let next = import.first()?; + let module = self.modules.get(&next.name)?; + + if import.len() > 1 { + module.get_module_from_import(&import[1..]) + } else { + Some(module) + } + } + + fn create_module_info(module: &Module, parent_name: Option) -> ModuleInfo<'_> { + let mut functions = HashMap::default(); + let mut constants = HashMap::default(); + let mut structs = HashMap::default(); + let mut types = HashMap::default(); + let mut child_modules = HashMap::default(); + let mut name = parent_name.clone().unwrap_or_default(); + + if name.is_empty() { + name = module.name.name.clone(); + } else { + name.push_str(&format!("::{}", module.name.name)); + } + + for stmt in &module.contents { + match stmt { + ModuleDefItem::Constant(info) => { + constants.insert(info.decl.name.name.clone(), info); + } + ModuleDefItem::Function(info) => { + functions.insert(info.decl.name.name.clone(), info); + } + ModuleDefItem::Struct(info) => { + structs.insert(info.name.name.clone(), info); + } + ModuleDefItem::Type(info) => { + types.insert(info.name.name.clone(), info); + } + ModuleDefItem::Module(info) => { + child_modules.insert( + info.name.name.clone(), + Self::create_module_info(info, Some(name.clone())), + ); + } + } + } + + ModuleInfo { + name, + functions, + structs, + constants, + types, + modules: child_modules, + } + } +} diff --git a/crates/concrete_check/src/lib.rs b/crates/concrete_check/src/lib.rs new file mode 100644 index 0000000..2dbeb84 --- /dev/null +++ b/crates/concrete_check/src/lib.rs @@ -0,0 +1,101 @@ +use std::{collections::HashMap, ops::Range}; + +use ariadne::{ColorGenerator, Label, Report, ReportKind}; +use ast_helper::AstHelper; +use concrete_ast::{imports::ImportStmt, modules::Module, Program}; +use concrete_session::Session; +use itertools::Itertools; +use thiserror::Error; + +mod ast_helper; + +#[derive(Error, Debug, Clone)] +pub enum CheckError<'p> { + #[error("import not found {:?} in module {}", import, module.name.name)] + ImportModuleMissing { + module: &'p Module, + import: &'p ImportStmt, + }, +} + +impl<'p> CheckError<'p> { + pub fn to_report<'s>(&self, session: &'s Session) -> Report<'s, (String, Range)> { + let path = session.file_path.display().to_string(); + let mut colors = ColorGenerator::new(); + colors.next(); + + match self { + CheckError::ImportModuleMissing { module, import } => { + let contex_module_span = module.span; + let span = { + let mut span = import + .module + .first() + .expect("module path can't be empty") + .span; + span.to = import + .module + .last() + .expect("module path can't be empty") + .span + .to; + span + }; + let offset = import.module[0].span.from; + Report::build(ReportKind::Error, path.clone(), offset) + .with_code("E1") + .with_label( + Label::new((path.clone(), contex_module_span.into())) + .with_message(format!("In module {:?}.", module.name.name)), + ) + .with_label( + Label::new((path, span.into())) + .with_message(format!( + "Module {:?} not found.", + import.module.iter().map(|x| &x.name).join(".") + )) + .with_color(colors.next()), + ) + .with_message("Failed to find import.") + .finish() + } + } + } +} + +pub fn check_program<'p>( + program: &'p Program, + _session: &Session, +) -> Result<(), Vec>> { + let helper = AstHelper::new(program); + + let mut errors = Vec::new(); + + for module in &program.modules { + // let info = helper.modules.get(&module.name.name).unwrap(); + + let mut imports = HashMap::new(); + + for import in &module.imports { + let target_module = helper.get_module_from_import(&import.module); + + if target_module.is_none() { + errors.push(CheckError::ImportModuleMissing { module, import }); + continue; + } + + let target_module = target_module.unwrap(); + + for symbol in &import.symbols { + // todo: check if symbol exists. + imports.insert(symbol.name.clone(), target_module); + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } +} diff --git a/crates/concrete_driver/Cargo.toml b/crates/concrete_driver/Cargo.toml index 35b9084..865d496 100644 --- a/crates/concrete_driver/Cargo.toml +++ b/crates/concrete_driver/Cargo.toml @@ -15,6 +15,7 @@ concrete_session = { path = "../concrete_session"} concrete_codegen_mlir = { path = "../concrete_codegen_mlir"} salsa = { git = "https://github.com/salsa-rs/salsa.git", package = "salsa-2022" } ariadne = { version = "0.4.0", features = ["auto-color"] } +concrete_check = { version = "0.1.0", path = "../concrete_check" } [dev-dependencies] tempfile = "3.9.0" diff --git a/crates/concrete_driver/src/lib.rs b/crates/concrete_driver/src/lib.rs index e293af0..cb29140 100644 --- a/crates/concrete_driver/src/lib.rs +++ b/crates/concrete_driver/src/lib.rs @@ -88,8 +88,20 @@ pub fn main() -> Result<(), Box> { target_dir, output_file, }; + tracing::debug!("Compiling with session: {:#?}", session); + if let Err(errors) = concrete_check::check_program(&program, &session) { + for error in &errors { + let path = session.file_path.display().to_string(); + error + .to_report(&session) + .eprint((path, session.source.clone()))?; + } + + std::process::exit(1); + } + let object_path = concrete_codegen_mlir::compile(&session, &program)?; if session.library { diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index 7bcda21..5bb7c78 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -188,12 +188,13 @@ pub Program: ast::Program = { // Modules pub(crate) Module: ast::modules::Module = { - "mod" "{" "}" => { + "mod" "{" "}" => { ast::modules::Module { doc_string: None, imports: imports.unwrap_or_else(Vec::new), name, - contents + contents, + span: Span::new(lo, hi), } } } @@ -208,10 +209,11 @@ pub(crate) ImportList: Vec = { pub(crate) ImportStmt: ast::imports::ImportStmt = { - "import" > "{" > "}" ";" => { + "import" > "{" > "}" ";" => { ast::imports::ImportStmt { module, symbols, + span: Span::new(lo, hi), } } } diff --git a/crates/concrete_type_checker/Cargo.toml b/crates/concrete_type_checker/Cargo.toml deleted file mode 100644 index 44762dd..0000000 --- a/crates/concrete_type_checker/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "concrete_type_checker" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/crates/concrete_type_checker/src/lib.rs b/crates/concrete_type_checker/src/lib.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/concrete_type_checker/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/missing_import.con b/examples/missing_import.con new file mode 100644 index 0000000..f299ba0 --- /dev/null +++ b/examples/missing_import.con @@ -0,0 +1,8 @@ +mod Simple { + import Other.{hello1}; + import Other.Deep.{hello2}; + + fn main() -> i64 { + return hello1(2) + hello2(2); + } +} From ffbf029ede7f6b4e102bedec074446a8f0d9a969 Mon Sep 17 00:00:00 2001 From: Edgar Date: Sat, 20 Jan 2024 23:46:49 +0100 Subject: [PATCH 7/9] more checks --- Cargo.lock | 1 + crates/concrete_check/src/lib.rs | 54 +++++++- crates/concrete_codegen_mlir/Cargo.toml | 1 + .../concrete_codegen_mlir/src/ast_helper.rs | 127 ------------------ crates/concrete_codegen_mlir/src/codegen.rs | 3 +- crates/concrete_codegen_mlir/src/lib.rs | 1 - crates/concrete_parser/src/grammar.lalrpop | 8 +- crates/concrete_parser/src/lib.rs | 27 +++- examples/missing_import.con | 11 ++ 9 files changed, 92 insertions(+), 141 deletions(-) delete mode 100644 crates/concrete_codegen_mlir/src/ast_helper.rs diff --git a/Cargo.lock b/Cargo.lock index 60fadbe..0b34ba8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -375,6 +375,7 @@ dependencies = [ "bumpalo", "cc", "concrete_ast", + "concrete_check", "concrete_session", "itertools 0.12.0", "llvm-sys", diff --git a/crates/concrete_check/src/lib.rs b/crates/concrete_check/src/lib.rs index 2dbeb84..9ea6c0e 100644 --- a/crates/concrete_check/src/lib.rs +++ b/crates/concrete_check/src/lib.rs @@ -2,12 +2,12 @@ use std::{collections::HashMap, ops::Range}; use ariadne::{ColorGenerator, Label, Report, ReportKind}; use ast_helper::AstHelper; -use concrete_ast::{imports::ImportStmt, modules::Module, Program}; +use concrete_ast::{common::Ident, imports::ImportStmt, modules::Module, Program}; use concrete_session::Session; use itertools::Itertools; use thiserror::Error; -mod ast_helper; +pub mod ast_helper; #[derive(Error, Debug, Clone)] pub enum CheckError<'p> { @@ -16,6 +16,12 @@ pub enum CheckError<'p> { module: &'p Module, import: &'p ImportStmt, }, + #[error("import symbol {:?} not found in module {}", symbol, module.name.name)] + ImportSymbolMissing { + module: &'p Module, + import: &'p ImportStmt, + symbol: &'p Ident, + }, } impl<'p> CheckError<'p> { @@ -59,6 +65,32 @@ impl<'p> CheckError<'p> { .with_message("Failed to find import.") .finish() } + CheckError::ImportSymbolMissing { + module, + import, + symbol, + } => { + let contex_module_span = module.span; + let import_span = import.span; + let offset = symbol.span.from; + Report::build(ReportKind::Error, path.clone(), offset) + .with_code("E1") + .with_label( + Label::new((path.clone(), contex_module_span.into())) + .with_message(format!("In module {:?}.", module.name.name)), + ) + .with_label( + Label::new((path.clone(), import_span.into())) + .with_message("In this import statement"), + ) + .with_label( + Label::new((path, symbol.span.into())) + .with_message(format!("Failed to find symbol {:?}", symbol.name)) + .with_color(colors.next()), + ) + .with_message("Failed to find import.") + .finish() + } } } } @@ -76,6 +108,7 @@ pub fn check_program<'p>( let mut imports = HashMap::new(); + // check modules for import in &module.imports { let target_module = helper.get_module_from_import(&import.module); @@ -86,8 +119,23 @@ pub fn check_program<'p>( let target_module = target_module.unwrap(); + // check if symbol exists for symbol in &import.symbols { - // todo: check if symbol exists. + let name = &symbol.name; + let exists = target_module.functions.get(name).is_some() + || target_module.constants.get(name).is_some() + || target_module.structs.get(name).is_some() + || target_module.types.get(name).is_some(); + + if !exists { + errors.push(CheckError::ImportSymbolMissing { + module, + import, + symbol, + }); + continue; + } + imports.insert(symbol.name.clone(), target_module); } } diff --git a/crates/concrete_codegen_mlir/Cargo.toml b/crates/concrete_codegen_mlir/Cargo.toml index 9df9c6f..6013882 100644 --- a/crates/concrete_codegen_mlir/Cargo.toml +++ b/crates/concrete_codegen_mlir/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] bumpalo = { version = "3.14.0", features = ["std"] } concrete_ast = { path = "../concrete_ast"} +concrete_check = { version = "0.1.0", path = "../concrete_check" } concrete_session = { path = "../concrete_session"} itertools = "0.12.0" llvm-sys = "170.0.1" diff --git a/crates/concrete_codegen_mlir/src/ast_helper.rs b/crates/concrete_codegen_mlir/src/ast_helper.rs deleted file mode 100644 index 0d8c6bd..0000000 --- a/crates/concrete_codegen_mlir/src/ast_helper.rs +++ /dev/null @@ -1,127 +0,0 @@ -use std::collections::HashMap; - -use concrete_ast::{ - common::Ident, - constants::ConstantDef, - functions::FunctionDef, - modules::{Module, ModuleDefItem}, - structs::StructDecl, - types::TypeDecl, - Program, -}; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ModuleInfo<'p> { - pub name: String, - pub functions: HashMap, - pub constants: HashMap, - pub structs: HashMap, - pub types: HashMap, - pub modules: HashMap>, -} - -impl<'p> ModuleInfo<'p> { - pub fn get_module_from_import(&self, import: &[Ident]) -> Option<&ModuleInfo<'p>> { - let next = import.first()?; - let module = self.modules.get(&next.name)?; - - if import.len() > 1 { - module.get_module_from_import(&import[1..]) - } else { - Some(module) - } - } - - /// Returns the symbol name from a local name. - pub fn get_symbol_name(&self, local_name: &str) -> String { - if local_name == "main" { - return local_name.to_string(); - } - - let mut result = self.name.clone(); - - result.push_str("::"); - result.push_str(local_name); - - result - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct AstHelper<'p> { - pub root: &'p Program, - pub modules: HashMap>, -} - -impl<'p> AstHelper<'p> { - pub fn new(root: &'p Program) -> Self { - let mut modules = HashMap::default(); - - for module in &root.modules { - modules.insert( - module.name.name.clone(), - Self::create_module_info(module, None), - ); - } - - Self { root, modules } - } - - pub fn get_module_from_import(&self, import: &[Ident]) -> Option<&ModuleInfo<'p>> { - let next = import.first()?; - let module = self.modules.get(&next.name)?; - - if import.len() > 1 { - module.get_module_from_import(&import[1..]) - } else { - Some(module) - } - } - - fn create_module_info(module: &Module, parent_name: Option) -> ModuleInfo<'_> { - let mut functions = HashMap::default(); - let mut constants = HashMap::default(); - let mut structs = HashMap::default(); - let mut types = HashMap::default(); - let mut child_modules = HashMap::default(); - let mut name = parent_name.clone().unwrap_or_default(); - - if name.is_empty() { - name = module.name.name.clone(); - } else { - name.push_str(&format!("::{}", module.name.name)); - } - - for stmt in &module.contents { - match stmt { - ModuleDefItem::Constant(info) => { - constants.insert(info.decl.name.name.clone(), info); - } - ModuleDefItem::Function(info) => { - functions.insert(info.decl.name.name.clone(), info); - } - ModuleDefItem::Struct(info) => { - structs.insert(info.name.name.clone(), info); - } - ModuleDefItem::Type(info) => { - types.insert(info.name.name.clone(), info); - } - ModuleDefItem::Module(info) => { - child_modules.insert( - info.name.name.clone(), - Self::create_module_info(info, Some(name.clone())), - ); - } - } - } - - ModuleInfo { - name, - functions, - structs, - constants, - types, - modules: child_modules, - } - } -} diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 0db203f..13e74ad 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -11,6 +11,7 @@ use concrete_ast::{ types::TypeSpec, Program, }; +use concrete_check::ast_helper::{AstHelper, ModuleInfo}; use concrete_session::Session; use melior::{ dialect::{ @@ -26,8 +27,6 @@ use melior::{ Context as MeliorContext, }; -use crate::ast_helper::{AstHelper, ModuleInfo}; - pub fn compile_program( session: &Session, ctx: &MeliorContext, diff --git a/crates/concrete_codegen_mlir/src/lib.rs b/crates/concrete_codegen_mlir/src/lib.rs index 372e73f..959807b 100644 --- a/crates/concrete_codegen_mlir/src/lib.rs +++ b/crates/concrete_codegen_mlir/src/lib.rs @@ -29,7 +29,6 @@ use llvm_sys::{ }; use module::MLIRModule; -mod ast_helper; mod codegen; mod context; mod error; diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index 5bb7c78..dc0b675 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -188,12 +188,12 @@ pub Program: ast::Program = { // Modules pub(crate) Module: ast::modules::Module = { - "mod" "{" "}" => { + "mod" "{" "}" => { ast::modules::Module { doc_string: None, imports: imports.unwrap_or_else(Vec::new), name, - contents, + contents: contents.unwrap_or_else(Vec::new), span: Span::new(lo, hi), } } @@ -270,7 +270,7 @@ pub(crate) Param: ast::functions::Param = { pub(crate) FunctionDef: ast::functions::FunctionDef = { "fn" "(" > ")" "{" - + "}" => { ast::functions::FunctionDef { decl: ast::functions::FunctionDecl { @@ -280,7 +280,7 @@ pub(crate) FunctionDef: ast::functions::FunctionDef = { params, ret_type, }, - body: statements + body: statements.unwrap_or_else(Vec::new) } } } diff --git a/crates/concrete_parser/src/lib.rs b/crates/concrete_parser/src/lib.rs index d0b4e1b..f6fcb16 100644 --- a/crates/concrete_parser/src/lib.rs +++ b/crates/concrete_parser/src/lib.rs @@ -89,7 +89,7 @@ mod ModuleName { "##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); } #[test] @@ -104,7 +104,7 @@ mod ModuleName { }"##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); } #[test] @@ -116,7 +116,7 @@ mod ModuleName { }"##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); } #[test] @@ -128,6 +128,25 @@ mod ModuleName { }"##; let lexer = Lexer::new(source); let parser = grammar::ProgramParser::new(); - dbg!(parser.parse(lexer).unwrap()); + parser.parse(lexer).unwrap(); + } + + #[test] + fn parse_empty_mod() { + let source = r##"mod MyMod { +}"##; + let lexer = Lexer::new(source); + let parser = grammar::ProgramParser::new(); + parser.parse(lexer).unwrap(); + } + + #[test] + fn parse_empty_fn() { + let source = r##"mod MyMod { + fn hello() {} +}"##; + let lexer = Lexer::new(source); + let parser = grammar::ProgramParser::new(); + parser.parse(lexer).unwrap(); } } diff --git a/examples/missing_import.con b/examples/missing_import.con index f299ba0..3987d99 100644 --- a/examples/missing_import.con +++ b/examples/missing_import.con @@ -1,8 +1,19 @@ mod Simple { import Other.{hello1}; import Other.Deep.{hello2}; + import Hello.{world}; fn main() -> i64 { return hello1(2) + hello2(2); } } + +mod Hello { + fn a() { + return 1; + } +} + +mod A { + +} From bb99fd4cf4c14697bdd1834147943ece158f384e Mon Sep 17 00:00:00 2001 From: Edgar Date: Sun, 21 Jan 2024 10:35:26 +0100 Subject: [PATCH 8/9] more checks --- crates/concrete_ast/src/functions.rs | 3 +- crates/concrete_ast/src/types.rs | 8 + crates/concrete_check/src/lib.rs | 333 +++++++++++++++--- crates/concrete_codegen_mlir/src/codegen.rs | 22 +- crates/concrete_driver/src/lib.rs | 2 +- crates/concrete_parser/src/grammar.lalrpop | 7 +- .../{missing_import.con => check_errors.con} | 4 + 7 files changed, 327 insertions(+), 52 deletions(-) rename examples/{missing_import.con => check_errors.con} (87%) diff --git a/crates/concrete_ast/src/functions.rs b/crates/concrete_ast/src/functions.rs index 3635665..c0e1539 100644 --- a/crates/concrete_ast/src/functions.rs +++ b/crates/concrete_ast/src/functions.rs @@ -1,5 +1,5 @@ use crate::{ - common::{DocString, GenericParam, Ident}, + common::{DocString, GenericParam, Ident, Span}, statements::Statement, types::TypeSpec, }; @@ -17,6 +17,7 @@ pub struct FunctionDecl { pub struct FunctionDef { pub decl: FunctionDecl, pub body: Vec, + pub span: Span, } #[derive(Clone, Debug, Eq, Hash, PartialEq)] diff --git a/crates/concrete_ast/src/types.rs b/crates/concrete_ast/src/types.rs index 2ae7c87..6454c4a 100644 --- a/crates/concrete_ast/src/types.rs +++ b/crates/concrete_ast/src/types.rs @@ -35,6 +35,14 @@ impl TypeSpec { TypeSpec::Array { is_ref, .. } => *is_ref, } } + + pub fn get_name(&self) -> String { + match self { + TypeSpec::Simple { name, .. } => name.name.clone(), + TypeSpec::Generic { name, .. } => name.name.clone(), + TypeSpec::Array { of_type, .. } => format!("[{}]", of_type.get_name()), + } + } } #[derive(Clone, Debug, Eq, Hash, PartialEq)] diff --git a/crates/concrete_check/src/lib.rs b/crates/concrete_check/src/lib.rs index 9ea6c0e..91f6227 100644 --- a/crates/concrete_check/src/lib.rs +++ b/crates/concrete_check/src/lib.rs @@ -1,8 +1,17 @@ use std::{collections::HashMap, ops::Range}; use ariadne::{ColorGenerator, Label, Report, ReportKind}; -use ast_helper::AstHelper; -use concrete_ast::{common::Ident, imports::ImportStmt, modules::Module, Program}; +use ast_helper::{AstHelper, ModuleInfo}; +use concrete_ast::{ + common::{Ident, Span}, + constants::{ConstantDecl, ConstantDef}, + functions::{FunctionDecl, FunctionDef}, + imports::ImportStmt, + modules::{Module, ModuleDefItem}, + statements::Statement, + types::TypeSpec, + Program, +}; use concrete_session::Session; use itertools::Itertools; use thiserror::Error; @@ -10,21 +19,20 @@ use thiserror::Error; pub mod ast_helper; #[derive(Error, Debug, Clone)] -pub enum CheckError<'p> { +pub enum CheckError { #[error("import not found {:?} in module {}", import, module.name.name)] - ImportModuleMissing { - module: &'p Module, - import: &'p ImportStmt, - }, + ImportModuleMissing { module: Module, import: ImportStmt }, #[error("import symbol {:?} not found in module {}", symbol, module.name.name)] ImportSymbolMissing { - module: &'p Module, - import: &'p ImportStmt, - symbol: &'p Ident, + module: Module, + import: ImportStmt, + symbol: Ident, }, + #[error("type not found {:?}", type_spec)] + TypeNotFound { type_spec: TypeSpec }, } -impl<'p> CheckError<'p> { +impl CheckError { pub fn to_report<'s>(&self, session: &'s Session) -> Report<'s, (String, Range)> { let path = session.file_path.display().to_string(); let mut colors = ColorGenerator::new(); @@ -62,7 +70,7 @@ impl<'p> CheckError<'p> { )) .with_color(colors.next()), ) - .with_message("Failed to find import.") + .with_message("Unresolved import.") .finish() } CheckError::ImportSymbolMissing { @@ -74,7 +82,7 @@ impl<'p> CheckError<'p> { let import_span = import.span; let offset = symbol.span.from; Report::build(ReportKind::Error, path.clone(), offset) - .with_code("E1") + .with_code("E2") .with_label( Label::new((path.clone(), contex_module_span.into())) .with_message(format!("In module {:?}.", module.name.name)), @@ -88,56 +96,248 @@ impl<'p> CheckError<'p> { .with_message(format!("Failed to find symbol {:?}", symbol.name)) .with_color(colors.next()), ) - .with_message("Failed to find import.") + .with_message("Unresolved import.") + .finish() + } + CheckError::TypeNotFound { type_spec } => { + let span = match type_spec { + TypeSpec::Simple { span, .. } => span, + TypeSpec::Generic { span, .. } => span, + TypeSpec::Array { span, .. } => span, + }; + Report::build(ReportKind::Error, path.clone(), span.from) + .with_code("E3") + .with_label( + Label::new((path, (*span).into())) + .with_message(format!("Failed to find type {:?}", type_spec.get_name())) + .with_color(colors.next()), + ) + .with_message(format!("Unresolved type {:?}.", type_spec.get_name())) .finish() } } } } -pub fn check_program<'p>( - program: &'p Program, - _session: &Session, -) -> Result<(), Vec>> { +#[derive(Debug, Clone)] +struct ScopeContext<'parent> { + pub locals: HashMap, + pub function: Option, + pub imports: HashMap>, + pub module_info: &'parent ModuleInfo<'parent>, +} + +#[derive(Debug, Clone)] +struct LocalVar { + pub type_spec: TypeSpec, +} + +impl<'parent> ScopeContext<'parent> { + /// Returns the symbol name from a local name. + pub fn get_symbol_name(&self, local_name: &str) -> String { + if local_name == "main" { + return local_name.to_string(); + } + + if let Some(module) = self.imports.get(local_name) { + // a import + module.get_symbol_name(local_name) + } else { + let mut result = self.module_info.name.clone(); + + result.push_str("::"); + result.push_str(local_name); + + result + } + } + + pub fn get_function(&self, local_name: &str) -> Option<&FunctionDef> { + if let Some(module) = self.imports.get(local_name) { + // a import + module.functions.get(local_name).copied() + } else { + self.module_info.functions.get(local_name).copied() + } + } + + fn resolve_type(&self, name: &str) -> Option { + Some(match name { + "u64" | "i64" => name.to_string(), + "u32" | "i32" => name.to_string(), + "u16" | "i16" => name.to_string(), + "u8" | "i8" => name.to_string(), + "f32" => name.to_string(), + "f64" => name.to_string(), + "bool" => name.to_string(), + name => { + if let Some(module) = self.imports.get(name) { + // a import + self.resolve_type_spec(&module.types.get(name)?.value)? + } else { + self.resolve_type_spec(&self.module_info.types.get(name)?.value)? + } + } + }) + } + + fn resolve_type_spec(&self, spec: &TypeSpec) -> Option { + match spec.is_ref() { + Some(_) => Some(format!("&{}", self.resolve_type_spec_ref(spec)?)), + None => self.resolve_type_spec_ref(spec), + } + } + + /// Resolves the type this ref points to. + fn resolve_type_spec_ref(&self, spec: &TypeSpec) -> Option { + match spec { + TypeSpec::Simple { name, .. } => self.resolve_type(&name.name), + TypeSpec::Generic { name, .. } => self.resolve_type(&name.name), + TypeSpec::Array { .. } => { + todo!("implement arrays") + } + } + } + + fn is_type_signed(&self, type_info: &TypeSpec) -> bool { + let signed = ["i8", "i16", "i32", "i64", "i128"]; + match type_info { + TypeSpec::Simple { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Array { .. } => unreachable!(), + } + } + + fn is_float(&self, type_info: &TypeSpec) -> bool { + let signed = ["f32", "f64"]; + match type_info { + TypeSpec::Simple { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), + TypeSpec::Array { .. } => unreachable!(), + } + } +} + +pub fn check_program(program: &Program) -> Result<(), Vec> { let helper = AstHelper::new(program); let mut errors = Vec::new(); for module in &program.modules { - // let info = helper.modules.get(&module.name.name).unwrap(); + let module_info = helper.modules.get(&module.name.name).unwrap(); + if let Err(e) = check_module(module, &helper, module_info) { + errors.extend(e); + } + } - let mut imports = HashMap::new(); + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } +} + +pub fn check_module<'p, 'x: 'p>( + module: &Module, + helper: &AstHelper<'p>, + module_info: &ModuleInfo<'p>, +) -> Result<(), Vec> { + let mut errors = Vec::new(); - // check modules - for import in &module.imports { - let target_module = helper.get_module_from_import(&import.module); + let mut scope_ctx = ScopeContext { + locals: HashMap::new(), + function: None, + imports: HashMap::new(), + module_info, + }; + + // check modules + for import in &module.imports { + let target_module = helper.get_module_from_import(&import.module); + + if target_module.is_none() { + errors.push(CheckError::ImportModuleMissing { + module: module.clone(), + import: import.clone(), + }); + continue; + } - if target_module.is_none() { - errors.push(CheckError::ImportModuleMissing { module, import }); + let target_module = target_module.unwrap(); + + // check if symbol exists + for symbol in &import.symbols { + let name = &symbol.name; + let exists = target_module.functions.get(name).is_some() + || target_module.constants.get(name).is_some() + || target_module.structs.get(name).is_some() + || target_module.types.get(name).is_some(); + + if !exists { + errors.push(CheckError::ImportSymbolMissing { + module: module.clone(), + import: import.clone(), + symbol: symbol.clone(), + }); continue; } - let target_module = target_module.unwrap(); - - // check if symbol exists - for symbol in &import.symbols { - let name = &symbol.name; - let exists = target_module.functions.get(name).is_some() - || target_module.constants.get(name).is_some() - || target_module.structs.get(name).is_some() - || target_module.types.get(name).is_some(); - - if !exists { - errors.push(CheckError::ImportSymbolMissing { - module, - import, - symbol, - }); - continue; - } + scope_ctx.imports.insert(symbol.name.clone(), target_module); + } + } - imports.insert(symbol.name.clone(), target_module); + for stmt in &module.contents { + match stmt { + ModuleDefItem::Constant(info) => { + if let Err(e) = check_constant(info, &scope_ctx, helper, module_info) { + errors.extend(e); + } } + ModuleDefItem::Function(info) => { + scope_ctx.function = Some(info.clone()); + if let Err(e) = check_function(info, &scope_ctx, helper, module_info) { + errors.extend(e); + } + } + ModuleDefItem::Struct(_) => {} + ModuleDefItem::Type(_) => {} + ModuleDefItem::Module(info) => { + let module_info = module_info.modules.get(&info.name.name).unwrap(); + if let Err(e) = check_module(info, helper, module_info) { + errors.extend(e); + } + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } +} + +fn check_function<'p>( + info: &FunctionDef, + scope_ctx: &ScopeContext<'p>, + helper: &AstHelper<'p>, + module_info: &ModuleInfo<'p>, +) -> Result<(), Vec> { + let mut errors = Vec::new(); + + for param in &info.decl.params { + if scope_ctx.resolve_type_spec(¶m.r#type).is_none() { + errors.push(CheckError::TypeNotFound { + type_spec: param.r#type.clone(), + }) + } + } + + if let Some(ret_type) = info.decl.ret_type.as_ref() { + if scope_ctx.resolve_type_spec(ret_type).is_none() { + errors.push(CheckError::TypeNotFound { + type_spec: ret_type.clone(), + }) } } @@ -147,3 +347,48 @@ pub fn check_program<'p>( Err(errors) } } + +fn check_constant<'p>( + info: &ConstantDef, + scope_ctx: &ScopeContext<'p>, + helper: &AstHelper<'p>, + module_info: &ModuleInfo<'p>, +) -> Result<(), Vec> { + let mut errors = Vec::new(); + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } +} + +fn check_statement<'p>( + info: &Statement, + scope_ctx: &mut ScopeContext<'p>, + helper: &AstHelper<'p>, + module_info: &ModuleInfo<'p>, +) -> Result<(), Vec> { + let mut errors = Vec::new(); + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } +} + +fn check_template<'p>( + function: &FunctionDecl, + scope_ctx: &mut ScopeContext<'p>, + helper: &AstHelper<'_>, + module_info: &ModuleInfo<'_>, +) -> Result<(), Vec> { + let mut errors = Vec::new(); + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } +} diff --git a/crates/concrete_codegen_mlir/src/codegen.rs b/crates/concrete_codegen_mlir/src/codegen.rs index 13e74ad..4bcae6f 100644 --- a/crates/concrete_codegen_mlir/src/codegen.rs +++ b/crates/concrete_codegen_mlir/src/codegen.rs @@ -135,7 +135,25 @@ impl<'ctx, 'parent> ScopeContext<'ctx, 'parent> { "f32" => Type::float32(context), "f64" => Type::float64(context), "bool" => IntegerType::new(context, 1).into(), - _ => todo!("custom type lookup"), + name => { + if let Some(module) = self.imports.get(name) { + // a import + self.resolve_type_spec( + context, + &module.types.get(name).expect("failed to find type").value, + )? + } else { + self.resolve_type_spec( + context, + &self + .module_info + .types + .get(name) + .expect("failed to find type") + .value, + )? + } + } }) } @@ -197,8 +215,6 @@ fn compile_module( module_info: &ModuleInfo<'_>, module: &Module, ) -> Result<(), Box> { - // todo: handle imports - let body = mlir_module.body(); let mut imports = HashMap::new(); diff --git a/crates/concrete_driver/src/lib.rs b/crates/concrete_driver/src/lib.rs index cb29140..e959e44 100644 --- a/crates/concrete_driver/src/lib.rs +++ b/crates/concrete_driver/src/lib.rs @@ -91,7 +91,7 @@ pub fn main() -> Result<(), Box> { tracing::debug!("Compiling with session: {:#?}", session); - if let Err(errors) = concrete_check::check_program(&program, &session) { + if let Err(errors) = concrete_check::check_program(&program) { for error in &errors { let path = session.file_path.display().to_string(); error diff --git a/crates/concrete_parser/src/grammar.lalrpop b/crates/concrete_parser/src/grammar.lalrpop index dc0b675..e9ffbd8 100644 --- a/crates/concrete_parser/src/grammar.lalrpop +++ b/crates/concrete_parser/src/grammar.lalrpop @@ -269,9 +269,9 @@ pub(crate) Param: ast::functions::Param = { } pub(crate) FunctionDef: ast::functions::FunctionDef = { - "fn" "(" > ")" "{" + "fn" "(" > ")" "{" - "}" => { + "}" => { ast::functions::FunctionDef { decl: ast::functions::FunctionDecl { doc_string: None, @@ -280,7 +280,8 @@ pub(crate) FunctionDef: ast::functions::FunctionDef = { params, ret_type, }, - body: statements.unwrap_or_else(Vec::new) + body: statements.unwrap_or_else(Vec::new), + span: Span::new(lo, hi), } } } diff --git a/examples/missing_import.con b/examples/check_errors.con similarity index 87% rename from examples/missing_import.con rename to examples/check_errors.con index 3987d99..47fb23f 100644 --- a/examples/missing_import.con +++ b/examples/check_errors.con @@ -6,6 +6,10 @@ mod Simple { fn main() -> i64 { return hello1(2) + hello2(2); } + + fn lol(a: x) -> b { + + } } mod Hello { From b6f342061c72f04a1926ce9d15b11bff77518f8a Mon Sep 17 00:00:00 2001 From: Edgar Date: Mon, 22 Jan 2024 09:34:48 -0300 Subject: [PATCH 9/9] fmt --- crates/concrete_check/src/lib.rs | 87 +++++++------------------------- 1 file changed, 19 insertions(+), 68 deletions(-) diff --git a/crates/concrete_check/src/lib.rs b/crates/concrete_check/src/lib.rs index 91f6227..a5f02c7 100644 --- a/crates/concrete_check/src/lib.rs +++ b/crates/concrete_check/src/lib.rs @@ -3,9 +3,9 @@ use std::{collections::HashMap, ops::Range}; use ariadne::{ColorGenerator, Label, Report, ReportKind}; use ast_helper::{AstHelper, ModuleInfo}; use concrete_ast::{ - common::{Ident, Span}, - constants::{ConstantDecl, ConstantDef}, - functions::{FunctionDecl, FunctionDef}, + common::Ident, + constants::ConstantDef, + functions::FunctionDef, imports::ImportStmt, modules::{Module, ModuleDefItem}, statements::Statement, @@ -119,6 +119,7 @@ impl CheckError { } } +#[allow(unused)] #[derive(Debug, Clone)] struct ScopeContext<'parent> { pub locals: HashMap, @@ -127,31 +128,14 @@ struct ScopeContext<'parent> { pub module_info: &'parent ModuleInfo<'parent>, } +#[allow(unused)] #[derive(Debug, Clone)] struct LocalVar { pub type_spec: TypeSpec, } +#[allow(unused)] impl<'parent> ScopeContext<'parent> { - /// Returns the symbol name from a local name. - pub fn get_symbol_name(&self, local_name: &str) -> String { - if local_name == "main" { - return local_name.to_string(); - } - - if let Some(module) = self.imports.get(local_name) { - // a import - module.get_symbol_name(local_name) - } else { - let mut result = self.module_info.name.clone(); - - result.push_str("::"); - result.push_str(local_name); - - result - } - } - pub fn get_function(&self, local_name: &str) -> Option<&FunctionDef> { if let Some(module) = self.imports.get(local_name) { // a import @@ -198,24 +182,6 @@ impl<'parent> ScopeContext<'parent> { } } } - - fn is_type_signed(&self, type_info: &TypeSpec) -> bool { - let signed = ["i8", "i16", "i32", "i64", "i128"]; - match type_info { - TypeSpec::Simple { name, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Array { .. } => unreachable!(), - } - } - - fn is_float(&self, type_info: &TypeSpec) -> bool { - let signed = ["f32", "f64"]; - match type_info { - TypeSpec::Simple { name, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Generic { name, .. } => signed.contains(&name.name.as_str()), - TypeSpec::Array { .. } => unreachable!(), - } - } } pub fn check_program(program: &Program) -> Result<(), Vec> { @@ -320,8 +286,8 @@ pub fn check_module<'p, 'x: 'p>( fn check_function<'p>( info: &FunctionDef, scope_ctx: &ScopeContext<'p>, - helper: &AstHelper<'p>, - module_info: &ModuleInfo<'p>, + _helper: &AstHelper<'p>, + _module_info: &ModuleInfo<'p>, ) -> Result<(), Vec> { let mut errors = Vec::new(); @@ -349,12 +315,12 @@ fn check_function<'p>( } fn check_constant<'p>( - info: &ConstantDef, - scope_ctx: &ScopeContext<'p>, - helper: &AstHelper<'p>, - module_info: &ModuleInfo<'p>, + _info: &ConstantDef, + _scope_ctx: &ScopeContext<'p>, + _helper: &AstHelper<'p>, + _module_info: &ModuleInfo<'p>, ) -> Result<(), Vec> { - let mut errors = Vec::new(); + let errors = Vec::new(); if errors.is_empty() { Ok(()) @@ -363,28 +329,13 @@ fn check_constant<'p>( } } -fn check_statement<'p>( - info: &Statement, - scope_ctx: &mut ScopeContext<'p>, - helper: &AstHelper<'p>, - module_info: &ModuleInfo<'p>, +fn _check_statement<'p>( + _info: &Statement, + _scope_ctx: &mut ScopeContext<'p>, + _helper: &AstHelper<'p>, + _module_info: &ModuleInfo<'p>, ) -> Result<(), Vec> { - let mut errors = Vec::new(); - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } -} - -fn check_template<'p>( - function: &FunctionDecl, - scope_ctx: &mut ScopeContext<'p>, - helper: &AstHelper<'_>, - module_info: &ModuleInfo<'_>, -) -> Result<(), Vec> { - let mut errors = Vec::new(); + let errors = Vec::new(); if errors.is_empty() { Ok(())