diff --git a/src/circuit_writer/ir.rs b/src/circuit_writer/ir.rs index 0561701e5..4d59526fb 100644 --- a/src/circuit_writer/ir.rs +++ b/src/circuit_writer/ir.rs @@ -113,6 +113,7 @@ impl Var { } /// Same as [crate::var::VarInfo], but with Term based Var. +#[derive(Debug)] pub enum VarOrRef { Var(Var), @@ -376,6 +377,7 @@ pub(crate) struct IRWriter { impl IRWriter { /// Same as circuit_writer::compile_stmt fn compile_stmt(&mut self, fn_env: &mut FnEnv, stmt: &Stmt) -> Result> { + dbg!("compile_stmt"); match &stmt.kind { StmtKind::Assign { mutable, lhs, rhs } => { // compute the rhs @@ -612,6 +614,7 @@ impl IRWriter { args, .. } => { + dbg!("impl IrWriter compute_expr"); // sanity check if fn_name.value == "main" { Err(self.error(ErrorKind::RecursiveMain, expr.span))? @@ -1017,6 +1020,41 @@ impl IRWriter { Ok(Some(var)) } + // TODO fix a duplicated code + ExprKind::ArrayLen { array } => { + // retrieve var of array + let var = self + .compute_expr(fn_env, array)? + .expect("array access on non-array"); + + // retrieve the type of the elements in the array + let array_typ = self.expr_type(array).expect("cannot find type of array"); + + let len = match array_typ { + TyKind::Array(_, array_len) => *array_len as usize, + _ => Err(Error::new( + "compute-expr", + ErrorKind::UnexpectedError("expected array"), + expr.span, + ))?, + }; + + let start = len; + + // out-of-bound checks + if start >= var.len() || start + len > var.len() { + return Err(self.error( + ErrorKind::ArrayIndexOutOfBounds(start, var.len()), + expr.span, + )); + } + + let var = var.narrow(start, len); + println!("impl IRWriter, compute_expr, ArrayLen, var: {:?}", var); + + Ok(Some(var)) + } + ExprKind::ArrayDeclaration(items) => { let mut cvars = vec![]; diff --git a/src/circuit_writer/writer.rs b/src/circuit_writer/writer.rs index 8f72a699a..b5c825bc4 100644 --- a/src/circuit_writer/writer.rs +++ b/src/circuit_writer/writer.rs @@ -118,6 +118,7 @@ impl CircuitWriter { fn_env: &mut FnEnv, stmt: &Stmt, ) -> Result>> { + dbg!("compile_stmt"); match &stmt.kind { StmtKind::Assign { mutable, lhs, rhs } => { // compute the rhs @@ -385,6 +386,7 @@ impl CircuitWriter { args, .. } => { + println!("impl CircuitWriter compute_expr"); // sanity check if fn_name.value == "main" { Err(self.error(ErrorKind::RecursiveMain, expr.span))? @@ -425,6 +427,7 @@ impl CircuitWriter { match &fn_info.kind { // assert() <-- for example FnKind::BuiltIn(sig, handle, _) => { + dbg!("compute_expr, FnKind::BuiltIn"); let res = handle(self, &sig.generics, &vars, expr.span); res.map(|r| r.map(VarOrRef::Var)) } @@ -775,6 +778,40 @@ impl CircuitWriter { Ok(Some(var)) } + // TODO declare a function, fix duplicated code + ExprKind::ArrayLen { array } => { + // retrieve var of array + let var = self + .compute_expr(fn_env, array)? + .expect("array access on non-array"); + + // retrieve the type of the elements in the array + let array_typ = self.expr_type(array).expect("cannot find type of array"); + + let len = match array_typ { + TyKind::Array(_, array_len) => *array_len as usize, + _ => Err(Error::new( + "compute-expr", + ErrorKind::UnexpectedError("expected array"), + expr.span, + ))?, + }; + + let start = len; + + // out-of-bound checks + if start >= var.len() || start + len > var.len() { + return Err(self.error( + ErrorKind::ArrayIndexOutOfBounds(start, var.len()), + expr.span, + )); + } + + let var = var.narrow(start, len); + + Ok(Some(var)) + } + ExprKind::ArrayDeclaration(items) => { let mut cvars = vec![]; diff --git a/src/compiler.rs b/src/compiler.rs index e1a2e13ec..527a95e9a 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -114,6 +114,7 @@ pub fn typecheck_next_file_inner( node_id: usize, server_mode: &mut Option, ) -> Result { + dbg!("typecheck_next_file_inner"); let is_lib = this_module.is_some(); // parsing to name resolution @@ -149,6 +150,7 @@ pub fn get_nast( node_id: usize, server_mode: &mut Option, ) -> Result<(NAST, usize)> { + dbg!("nast_pass"); // save filename and source code let filename_id = sources.add(filename.clone(), code); let code = &sources.map[&filename_id].1; @@ -166,6 +168,8 @@ pub fn get_nast( println!("lexer succeeded"); } + dbg!("nast_pass, lexer succeeded "); + // debug server if let Some(server_mode) = server_mode { server_mode.send( @@ -176,14 +180,27 @@ pub fn get_nast( let _ = server_mode.recv(); } + dbg!("nast_pass, debug server succeeded "); + println!("tokens: {:?}", tokens); + // parser - let (ast, new_node_id) = AST::parse(filename_id, tokens, node_id)?; - if std::env::var("NONAME_VERBOSE").is_ok() { - println!("parser succeeded"); - } + // let (ast, new_node_id) = AST::parse(filename_id, tokens, node_id)?; + // if std::env::var("NONAME_VERBOSE").is_ok() { + // println!("parser succeeded"); + // } + let (ast, new_node_id) = match AST::parse(filename_id, tokens, node_id) { + Ok((ast, new_node_id)) => (ast, new_node_id), + Err(err) => { + println!("AST::parse Error occurred: {}", err); + return Err(err); + } + }; + + dbg!("nast_pass, AST::parse succeeded "); // debug server if let Some(server_mode) = server_mode { + dbg!(" if let Some(server_mode) = server_mode {"); server_mode.send(format!("ast of {filename}"), &ast); // block on an answer let _ = server_mode.recv(); diff --git a/src/mast/mod.rs b/src/mast/mod.rs index 2bbedfd5a..8350ad260 100644 --- a/src/mast/mod.rs +++ b/src/mast/mod.rs @@ -187,11 +187,14 @@ impl FnInfo { observed_args: &[ExprMonoInfo], ctx: &mut MastCtx, ) -> Result { + dbg!("resolve_generic_signature"); match self.kind { FnKind::BuiltIn(ref mut sig, _, _) => { + println!("resolve_generic_signature, FnKind::BuiltIn, sig: {:?}", sig); sig.resolve_generic_values(observed_args, ctx)?; } FnKind::Native(ref mut func) => { + println!("resolve_generic_signature, FnKind::Native, func: {:?}", func); func.sig.resolve_generic_values(observed_args, ctx)?; } }; @@ -430,6 +433,7 @@ impl Mast { /// Returns the function info by fully qualified name. pub fn fn_info(&self, qualified: &FullyQualified) -> Option<&FnInfo> { + dbg!("imple Mast fn_info"); self.0.fn_info(qualified) } @@ -464,6 +468,7 @@ impl Mast { /// This is the entry point of the monomorphization process. /// It stores the monomorphized AST at the end. pub fn monomorphize(tast: TypeChecker) -> Result> { + println!("monomorphize"); let mut ctx = MastCtx::new(tast); let qualified = FullyQualified::local("main".to_string()); @@ -575,6 +580,8 @@ fn monomorphize_expr( args, unsafe_attr, } => { + dbg!("monomorphize_expr"); + println!("fn_name: {:?}", fn_name); // compute the observed arguments types let mut observed = Vec::with_capacity(args.len()); for arg in args { @@ -651,8 +658,10 @@ fn monomorphize_expr( method_name, args, } => { + dbg!("expr_mono"); // retrieve struct name on the lhs let lhs_mono = monomorphize_expr(ctx, lhs, mono_fn_env)?; + println!("lhs_mono: {:?}", lhs_mono); let (module, struct_name) = match lhs_mono.clone().typ { Some(TyKind::Custom { module, name }) => (module, name), _ => return Err(error(ErrorKind::MethodCallOnNonCustomStruct, expr.span)), @@ -959,6 +968,19 @@ fn monomorphize_expr( ExprMonoInfo::new(mexpr, el_typ, None) } + ExprKind::ArrayLen { array } => { + let array_mono = monomorphize_expr(ctx, array, mono_fn_env)?; + + let mexpr = expr.to_mast( + ctx, + &ExprKind::ArrayLen { + array: Box::new(array_mono.expr), + }, + ); + + ExprMonoInfo::new(mexpr, array_mono.typ, None) + } + ExprKind::ArrayDeclaration(items) => { let len: u32 = items.len().try_into().expect("array too large"); diff --git a/src/name_resolution/expr.rs b/src/name_resolution/expr.rs index d2630fe00..19353fb31 100644 --- a/src/name_resolution/expr.rs +++ b/src/name_resolution/expr.rs @@ -37,9 +37,18 @@ impl NameResCtx { } ExprKind::MethodCall { lhs, - method_name: _, + method_name, args, } => { + println!("resolve_expr, ExprKind::MethodCall, lhs: {:?}, method_name: {:?}, args: {:?}", lhs, method_name, args); + /* + + resolve_expr, ExprKind::MethodCall, lhs: Expr { node_id: 13, kind: Variable { module: Local, name: Ident { value: "array", span: Span { filename_id: 1, start: 168, len: 5 } } }, span: Span { filename_id: 1, start: 168, len: 5 } }, method_name: Ident { value: "len", span: Span { filename_id: 1, start: 174, len: 3 } }, args: [] + [src/type_checker/mod.rs:235:9] "TypeChecker.analyze" = "TypeChecker.analyze" + + + */ + self.resolve_expr(lhs)?; for arg in args { self.resolve_expr(arg)?; @@ -52,6 +61,11 @@ impl NameResCtx { ExprKind::FieldAccess { lhs, rhs: _ } => { self.resolve_expr(lhs)?; } + + // ExprKind::ArrayLen { array } => { + // self.resolve_expr(array)?; + // } + ExprKind::BinaryOp { op: _, lhs, @@ -80,6 +94,9 @@ impl NameResCtx { self.resolve_expr(expr)?; } } + ExprKind::ArrayLen { array} => { + self.resolve_expr(array)?; + } ExprKind::RepeatedArrayInit { item, size } => { self.resolve_expr(item)?; self.resolve_expr(size)?; diff --git a/src/name_resolution/mod.rs b/src/name_resolution/mod.rs index 0383cc5be..08bdbccf7 100644 --- a/src/name_resolution/mod.rs +++ b/src/name_resolution/mod.rs @@ -27,6 +27,7 @@ impl NAST { } pub fn resolve_modules(this_module: Option, mut ast: AST) -> Result> { + dbg!("resolve_modules"); let mut ctx = NameResCtx::new(this_module); // create a map of the imported modules (and how they are aliases) diff --git a/src/negative_tests.rs b/src/negative_tests.rs index dd557cf71..80fadc9b3 100644 --- a/src/negative_tests.rs +++ b/src/negative_tests.rs @@ -747,3 +747,105 @@ fn test_mut_cst_struct_field_prop() { ErrorKind::ArgumentTypeMismatch(..) )); } + +#[test] +fn test_array_len() { + let code = r#" + + fn init_arr(const LEN: Field) -> [Field; LEN + 2] { + return [0; LEN + 2]; + } + fn main(pub xx: Field) { + let array = init_arr(10); + assert_eq(array.len(), 12); + } + "#; + + + assert!(mast_pass(code).is_ok()); + // if let Err(err) = mast_pass(code) { + // println!("err: {:?}", err); + // } + + // assert_eq!(1, 2); + // assert!(matches!( + // res.unwrap_err().kind, + // ErrorKind::ArgumentTypeMismatch(..) + // )); +} + + +#[test] +fn test_custom_struct_len_method() { + let code = r#" + struct Thing { + aa: [Field; 2], + } + fn Thing.len() -> LEN { + return Thing.aa.len() + } + "#; + + if let Err(err) = tast_pass(code).0 { + println!("err: {:?}", err); + + } + + assert_eq!(1, 2); +} + +#[test] +fn test_custom_struct_invalid_len_method() { + let code = r#" + struct Thing { + aa: Field + } + fn Thing.len() -> LEN { + // yield an error cause aa is an aray + return Thing.aa.len() + } + "#; + + if let Err(err) = tast_pass(code).0 { + println!("err: {:?}", err); + + } + + + assert_eq!(1, 2); +} + + +#[test] +fn test_invalid_len_method() { + let code = r#" + fn main(pub xx: Field) { + assert_eq(xx.len(), 12); + } + "#; + + if let Err(err) = tast_pass(code).0 { + println!("err: {:?}", err); + + } + + assert_eq!(1, 2); +} + + +#[test] +// I guess, this is a bug +fn test_assert_eq() { + let code = r#" + fn main(pub xx: Field) { + let aa = xx + 10; + assert_eq(aa, xx); + } + "#; + assert!(tast_pass(code).0.is_ok()); + assert!(mast_pass(code).is_ok()); + // if let Err(err) = mast_pass(code) { + // println!("err: {:?}", err); + // } + //assert_eq!(1, 2); +} \ No newline at end of file diff --git a/src/parser/expr.rs b/src/parser/expr.rs index 27fd375ef..f75f02db6 100644 --- a/src/parser/expr.rs +++ b/src/parser/expr.rs @@ -69,10 +69,16 @@ pub enum ExprKind { }, /// `let lhs = rhs` - Assignment { lhs: Box, rhs: Box }, + Assignment { + lhs: Box, + rhs: Box, + }, /// `lhs.rhs` - FieldAccess { lhs: Box, rhs: Ident }, + FieldAccess { + lhs: Box, + rhs: Ident, + }, /// `lhs rhs` BinaryOp { @@ -95,17 +101,31 @@ pub enum ExprKind { /// a variable or a type. For example, `mod::A`, `x`, `y`, etc. // TODO: change to `identifier` or `path`? - Variable { module: ModulePath, name: Ident }, + Variable { + module: ModulePath, + name: Ident, + }, /// An array access, for example: /// `lhs[idx]` - ArrayAccess { array: Box, idx: Box }, + ArrayAccess { + array: Box, + idx: Box, + }, + + // `arr.len()` + ArrayLen { + array: Box, + }, /// `[ ... ]` ArrayDeclaration(Vec), /// `[item; size]` - RepeatedArrayInit { item: Box, size: Box }, + RepeatedArrayInit { + item: Box, + size: Box, + }, /// `name { fields }` CustomTypeDeclaration { @@ -139,6 +159,7 @@ pub enum Op2 { impl Expr { /// Parses until it finds something it doesn't know, then returns without consuming the token it doesn't know (the caller will have to make sense of it) pub fn parse(ctx: &mut ParserCtx, tokens: &mut Tokens) -> Result { + dbg!("Expr::parse"); let token = tokens.bump_err(ctx, ErrorKind::MissingExpression)?; let span = token.span; @@ -148,6 +169,9 @@ impl Expr { // identifier TokenKind::Identifier(value) => { + dbg!("Expression::parse(), match TokenKind::Identifier(value)"); + println!("value: {}", &value); + let maybe_module = Ident::new(value, span); // is it a qualified identifier? @@ -424,6 +448,7 @@ impl Expr { /// an expression is sometimes unfinished when we parse it with [Self::parse], /// we use this function to see if the expression we just parsed (`self`) is actually part of a bigger expression fn parse_rhs(self, ctx: &mut ParserCtx, tokens: &mut Tokens) -> Result { + dbg!("parse_rhs"); // we peek into what's next to see if there's an expression that uses // the expression `self` we just parsed. // warning: ALL of the rules here should make use of `self`. @@ -670,6 +695,8 @@ impl Expr { kind: TokenKind::Dot, .. }) => { + dbg!("parse_rhs, TokenKind::Dot"); + println!("self.kind : {:?}", self.kind); let period = tokens.bump(ctx).unwrap(); // . // sanitize @@ -685,7 +712,20 @@ impl Expr { // lhs.field // ^^^^^ + dbg!("parse_rhs, TokenKind::Dot, before Ident::parse(ctx, tokens)?;"); let rhs = Ident::parse(ctx, tokens)?; + dbg!("parse_rhs, TokenKind::Dot, after Ident::parse(ctx, tokens)?;"); + dbg!("parse_rhs, TokenKind::Dot, rhs: {:?}", rhs.clone()); + /* + [src/parser/expr.rs:718:17] rhs.clone() = Ident { + value: "len", + span: Span { + filename_id: 1, + start: 207, + len: 3, + }, + } + */ let span = self.span.merge_with(rhs.span); // lhs.field or lhs.method_name() @@ -699,18 +739,36 @@ impl Expr { .. }) => { // lhs.method_name(args) - // ^^^^ + // + dbg!("parse_rhs, TokenKind::Dot, lhs.method_name(args)"); let (args, end_span) = parse_fn_call_args(ctx, tokens)?; - - let span = span.merge_with(end_span); - - Expr::new( - ctx, + println!("args: {:?}, rhs: {:?}", args, rhs.clone()); + let kind = if rhs.value == "len" { + println!("if rhs.value == len, self.clone(): {:?}", self.clone()); + // TODO check if self is actually an array type + ExprKind::ArrayLen { + array: Box::new(self), + } + // ExprKind::FnCall { + // module: ModulePath::Local, + // fn_name: rhs, + // args, + // unsafe_attr: false, + // } + } else { ExprKind::MethodCall { lhs: Box::new(self), method_name: rhs, args, - }, + } + }; + + + + let span = span.merge_with(end_span); + Expr::new( + ctx, + kind, span, ) } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index e69ee0ee3..dc7baa971 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -106,6 +106,7 @@ impl AST { mut tokens: Tokens, node_id: usize, ) -> Result<(AST, usize)> { + dbg!("AST::parse"); let mut ast = vec![]; let ctx = &mut ParserCtx::new(filename_id, node_id); @@ -152,6 +153,7 @@ impl AST { // `fn main() { }` TokenKind::Keyword(Keyword::Fn) => { function_observed = true; + dbg!("parse, TokenKind::Keyword(Keyword::Fn)"); let func = FunctionDef::parse(ctx, &mut tokens)?; ast.push(Root { diff --git a/src/parser/types.rs b/src/parser/types.rs index 4b79db677..ad87fa0b7 100644 --- a/src/parser/types.rs +++ b/src/parser/types.rs @@ -101,6 +101,7 @@ pub fn parse_type_declaration( } pub fn parse_fn_call_args(ctx: &mut ParserCtx, tokens: &mut Tokens) -> Result<(Vec, Span)> { + dbg!("parse_fn_call_args"); let start = tokens.bump(ctx).expect("parser error: parse_fn_call_args"); // ( let mut span = start.span; @@ -285,7 +286,7 @@ pub enum TyKind { // Bool, // U8, // U16, - // U32, + // U32 // U64, /// An array with symbolic size. /// This is an intermediate type. @@ -668,6 +669,7 @@ impl Ident { } pub fn parse(ctx: &mut ParserCtx, tokens: &mut Tokens) -> Result { + dbg!("Ident.parse"); let token = tokens.bump_err(ctx, ErrorKind::MissingToken)?; match token.kind { TokenKind::Identifier(ident) => Ok(Self { @@ -1139,6 +1141,7 @@ impl FunctionDef { } pub fn parse_fn_body(ctx: &mut ParserCtx, tokens: &mut Tokens) -> Result> { + dbg!("parse_fn_body"); let mut body = vec![]; // return empty body when the next token is `;` instead of `{` @@ -1154,8 +1157,10 @@ impl FunctionDef { } tokens.bump_expected(ctx, TokenKind::LeftCurlyBracket)?; + dbg!("parse_fn_body, bump_expected"); loop { + dbg!("parse_fn_body, loop"); // end of the function let next_token = tokens.peek(); if matches!( @@ -1170,7 +1175,9 @@ impl FunctionDef { } // parse next statement + dbg!("parse_fn_body, loop, before Stmt::parse(ctx, tokens)?"); let statement = Stmt::parse(ctx, tokens)?; + dbg!("parse_fn_body, loop, after Stmt::parse(ctx, tokens)?"); body.push(statement); } @@ -1179,6 +1186,7 @@ impl FunctionDef { /// Parse a function, without the `fn` keyword. pub fn parse(ctx: &mut ParserCtx, tokens: &mut Tokens) -> Result { + dbg!("FunctionDef parse"); // ghetto way of getting the span of the function: get the span of the first token (name), then try to get the span of the last token let mut span = tokens .peek() @@ -1192,6 +1200,8 @@ impl FunctionDef { // parse signature let sig = FnSig::parse(ctx, tokens)?; + dbg!("FunctionDef parse, FnSig::parse succeded"); + println!("sig: {:?}", sig); // make sure that it doesn't shadow a builtin if BUILTIN_FN_NAMES.contains(&sig.name.value.as_ref()) { @@ -1203,6 +1213,9 @@ impl FunctionDef { // parse body let body = Self::parse_fn_body(ctx, tokens)?; + dbg!("FunctionDef parse, Self::parse_fn_body succeded"); + println!("body: {:?}", body); + // here's the last token, that is if the function is not empty (maybe we should disallow empty functions?) @@ -1222,6 +1235,8 @@ impl FunctionDef { is_hint: false, }; + println!("FunctionDef: {:?}", func); + Ok(func) } @@ -1528,6 +1543,7 @@ impl Stmt { // statement expression (like function call) _ => { + dbg!("Stmt::parse(), statement expression (like function call)"); let expr = Expr::parse(ctx, tokens)?; let span = expr.span; diff --git a/src/stdlib/builtins.rs b/src/stdlib/builtins.rs index 65e607cdd..d94dd038d 100644 --- a/src/stdlib/builtins.rs +++ b/src/stdlib/builtins.rs @@ -19,11 +19,13 @@ use crate::{ use super::{FnInfoType, Module}; pub const QUALIFIED_BUILTINS: &str = "std/builtins"; -pub const BUILTIN_FN_NAMES: [&str; 3] = ["assert", "assert_eq", "log"]; +pub const BUILTIN_FN_NAMES: [&str; 4] = ["assert", "assert_eq", "log", "len"]; const ASSERT_FN: &str = "assert(condition: Bool)"; const ASSERT_EQ_FN: &str = "assert_eq(lhs: Field, rhs: Field)"; const LOG_FN: &str = "log(var: Field)"; +const LEN_FN: &str = "len()"; + pub struct BuiltinsLib {} @@ -31,9 +33,11 @@ impl Module for BuiltinsLib { const MODULE: &'static str = "builtins"; fn get_fns() -> Vec<(&'static str, FnInfoType, bool)> { + dbg!("stdlib.builtin::get_fns()"); vec![ (ASSERT_FN, assert_fn, false), (ASSERT_EQ_FN, assert_eq_fn, false), + (LEN_FN, len_fn, false), // true -> skip argument type checking for log (LOG_FN, log_fn, true), ] @@ -47,10 +51,13 @@ fn assert_eq_fn( vars: &[VarInfo], span: Span, ) -> Result>> { + dbg!("assert_eq_fn"); // we get two vars assert_eq!(vars.len(), 2); let lhs_info = &vars[0]; let rhs_info = &vars[1]; + println!("assert_eq_fn, lhs_info: {:?}, rhs_info: {:?}", lhs_info, rhs_info); + // they are both of type field if !matches!(lhs_info.typ, Some(TyKind::Field { .. })) { @@ -165,3 +172,15 @@ fn log_fn( Ok(None) } + +/// Asserts that two vars are equal. +fn len_fn( + compiler: &mut CircuitWriter, + _generics: &GenericParameters, + vars: &[VarInfo], + span: Span, +) -> Result>> { + dbg!("len_fn invocation"); + Ok(None) +} + diff --git a/src/stdlib/mod.rs b/src/stdlib/mod.rs index 1c8dde950..73eff806f 100644 --- a/src/stdlib/mod.rs +++ b/src/stdlib/mod.rs @@ -74,6 +74,8 @@ trait Module { fn get_fns() -> Vec<(&'static str, FnInfoType, bool)>; fn get_parsed_fns() -> Vec> { + dbg!("get_parsed_fn calls get_fns"); + println!("Self::module: {:?}", Self::MODULE); let fns = Self::get_fns(); let mut res = Vec::with_capacity(fns.len()); for (code, fn_handle, ignore_arg_types) in fns { diff --git a/src/type_checker/checker.rs b/src/type_checker/checker.rs index 150072bdd..fe1598724 100644 --- a/src/type_checker/checker.rs +++ b/src/type_checker/checker.rs @@ -99,7 +99,20 @@ impl TypeChecker { expr: &Expr, typed_fn_env: &mut TypedFnEnv, ) -> Result> { + dbg!("compute type"); let typ: Option = match &expr.kind { + ExprKind::ArrayLen { array } => { + // array: Expr { node_id: 14, kind: ArrayLen { array: Expr { node_id: 13, kind: Variable { module: Local, name: Ident { value: "array", span: Span { filename_id: 1, start: 201, len: 5 } } }, span: Span { filename_id: 1, start: 201, len: 5 } } }, span: Span { filename_id: 1, start: 201, len: 9 } }, + + let array_node = self + .compute_type(array, typed_fn_env)? + .expect("type-checker bug: field access on an empty var"); + + let expr_ty_info = ExprTyInfo::new(array_node.var_name, array_node.typ); + println!("compute_type, ArrayLen, expr_ty_info: {:?}", expr_ty_info); + + Some(expr_ty_info) + } ExprKind::FieldAccess { lhs, rhs } => { // compute type of left-hand side let lhs_node = self @@ -109,9 +122,19 @@ impl TypeChecker { // obtain the type of the field let (module, struct_name) = match lhs_node.typ { TyKind::Custom { module, name } => (module, name), - _ => return Err(self.error(ErrorKind::FieldAccessOnNonCustomStruct, expr.span)), + _ => { + dbg!("compute type, FieldAccessOnNonCustomStruct"); + //lhs: Expr { node_id: 13, kind: Variable { module: Local, name: Ident { value: "arr", span: Span { filename_id: 1, start: 181, len: 3 } } }, span: Span { filename_id: 1, start: 181, len: 3 } }, + // rhs: Ident { value: "len", span: Span { filename_id: 1, start: 185, len: 3 } } + println!("lhs: {:?}, rhs: {:?}", lhs, rhs); + return Err(self.error(ErrorKind::FieldAccessOnNonCustomStruct, expr.span)); + } }; + println!( + "compute_type, FieldAccess, module: {:?}, struct_name: {}", + module, struct_name + ); // get struct info let qualified = FullyQualified::new(&module, &struct_name); let struct_info = self @@ -126,7 +149,12 @@ impl TypeChecker { .map(|(_, typ)| typ.clone()); if let Some(res) = res { - Some(ExprTyInfo::new(lhs_node.var_name, res)) + let expr_ty_info = ExprTyInfo::new(lhs_node.var_name, res); + println!( + "compute_type, FieldAccess, expr_ty_info: {:?}", + expr_ty_info + ); + Some(expr_ty_info) } else { return Err(self.error( ErrorKind::UndefinedField(struct_info.name.clone(), rhs.value.clone()), @@ -142,15 +170,20 @@ impl TypeChecker { args, unsafe_attr, } => { + dbg!("impl TypeChecker compute_type, match ExprKind::FnCall"); + println!("fn_name: {:?}", fn_name); // retrieve the function signature let qualified = FullyQualified::new(&module, &fn_name.value); + println!("qualified: {:?}", qualified); let fn_info = self.fn_info(&qualified).ok_or_else(|| { self.error( ErrorKind::UndefinedFunction(fn_name.value.clone()), fn_name.span, ) })?; + let fn_sig = fn_info.sig().clone(); + println!("fn_sig: {:?}", fn_sig); // check if the function is a hint if fn_info.is_hint && !unsafe_attr { @@ -164,7 +197,9 @@ impl TypeChecker { // check if generic is allowed if fn_sig.require_monomorphization() && typed_fn_env.is_in_forloop() { + dbg!("if fn_sig.require_monomorphization() && typed_fn_env.is_in_forloop()"); for (observed_arg, expected_arg) in args.iter().zip(fn_sig.arguments.iter()) { + println!("for loop"); // check if the arg involves generic vars if !expected_arg.extract_generic_names().is_empty() { let mut forbidden_env = typed_fn_env.clone(); @@ -348,9 +383,10 @@ impl TypeChecker { let (module, struct_name) = match lhs_node.typ { TyKind::Custom { module, name } => (module, name), _ => { + dbg!("if let ExprKind::FieldAccess, ErrorKind::FieldAccessOnNonCustomStruct"); return Err( self.error(ErrorKind::FieldAccessOnNonCustomStruct, lhs.span) - ) + ); } }; @@ -463,6 +499,7 @@ impl TypeChecker { } ExprKind::ArrayAccess { array, idx } => { + dbg!("array access"); // get type of lhs let typ = self.compute_type(array, typed_fn_env)?.unwrap(); @@ -825,6 +862,8 @@ impl TypeChecker { args: &[Expr], span: Span, ) -> Result> { + dbg!("check_fn_call"); + println!("fn_sig: {:?}", fn_sig); // check if a function names is in use already by another variable match typed_fn_env.get_type_info(&fn_sig.name.value)? { Some(_) => { @@ -866,10 +905,13 @@ impl TypeChecker { if let Some(node) = self.compute_type(arg, typed_fn_env)? { observed.push((node.typ.clone(), arg.span)); } else { + dbg!("check_fn_call "); return Err(self.error(ErrorKind::CannotComputeExpression, arg.span)); } } + println!("observed_len"); + // check argument length if expected.len() != observed.len() { return Err(self.error( @@ -884,6 +926,7 @@ impl TypeChecker { for (sig_arg, (typ, span)) in expected.iter().zip(observed) { // when const attribute presented, the argument must be a constant if sig_arg.is_constant() && !matches!(typ, TyKind::Field { constant: true }) { + dbg!("if sig_arg.is_constant() && !matches!(typ, TyKind::Field { constant: true })"); return Err(self.error( ErrorKind::ArgumentTypeMismatch(sig_arg.typ.kind.clone(), typ), span, @@ -891,6 +934,8 @@ impl TypeChecker { } if !typ.match_expected(&sig_arg.typ.kind, false) { + dbg!("if !typ.match_expected(&sig_arg.typ.kind, false)"); + println!("&sig_arg.typ.kind: {:?}", &sig_arg.typ.kind); return Err(self.error( ErrorKind::ArgumentTypeMismatch(sig_arg.typ.kind.clone(), typ), span, diff --git a/src/type_checker/mod.rs b/src/type_checker/mod.rs index baa5ee9fa..227ed250d 100644 --- a/src/type_checker/mod.rs +++ b/src/type_checker/mod.rs @@ -207,7 +207,9 @@ impl TypeChecker { let module_path = ModulePath::Absolute(UserRepo::new(&format!("std/{}", module_impl.get_name()))); for fn_info in module_impl.get_parsed_fns() { + dbg!("TypeChecker.new::get_parsed_fns, insert new entry in typechecker.functions HashMap"); let qualified = FullyQualified::new(&module_path, &fn_info.sig().name.value); + println!("qualified: {:?}", qualified); if type_checker .functions .insert(qualified, fn_info.clone()) @@ -230,6 +232,7 @@ impl TypeChecker { /// - resolves imports /// - type checks pub fn analyze(&mut self, nast: NAST, is_lib: bool) -> Result<()> { + dbg!("TypeChecker.analyze"); // // Process constants // @@ -328,6 +331,7 @@ impl TypeChecker { match &root.kind { // `fn main() { ... }` RootKind::FunctionDef(function) => { + println!("TypeChecker.analyze(), match RootKind.FunctionDef, function: {:?}", function); // create a new typed fn environment to type check the function let mut typed_fn_env = TypedFnEnv::default();