diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index 92a2d16e17d8eb47928441263ec11b6b5b3b93d5..50c394d05e6ca7b4b17c7e1e4e99b3fd14c04571 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -808,8 +808,10 @@ impl Default for ConcreteType { } } +// TODO: Remove at some point #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum PrimitiveType { + Unassigned, Input, Output, Message, @@ -845,6 +847,8 @@ pub struct Type { #[allow(dead_code)] impl Type { + pub const UNASSIGNED: Type = Type { primitive: PrimitiveType::Unassigned, array: false }; + pub const INPUT: Type = Type { primitive: PrimitiveType::Input, array: false }; pub const OUTPUT: Type = Type { primitive: PrimitiveType::Output, array: false }; pub const MESSAGE: Type = Type { primitive: PrimitiveType::Message, array: false }; @@ -867,6 +871,9 @@ impl Type { impl Display for Type { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match &self.primitive { + PrimitiveType::Unassigned => { + write!(f, "unassigned")?; + } PrimitiveType::Input => { write!(f, "in")?; } @@ -1621,7 +1628,6 @@ pub struct MemoryStatement { // Phase 1: parser pub position: InputPosition, pub variable: LocalId, - pub initial: ExpressionId, // Phase 2: linker pub next: Option, } @@ -1916,7 +1922,6 @@ impl SyntaxElement for ExpressionStatement { #[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)] pub enum ExpressionParent { None, // only set during initial parsing - Memory(MemoryStatementId), If(IfStatementId), While(WhileStatementId), Return(ReturnStatementId), diff --git a/src/protocol/ast_printer.rs b/src/protocol/ast_printer.rs index 8dbfc6f0900fef9dfc31ac07df4855cf5e1b0991..03710204ad1a43957138e3b87f5b701811d95a97 100644 --- a/src/protocol/ast_printer.rs +++ b/src/protocol/ast_printer.rs @@ -361,8 +361,6 @@ impl ASTWriter { self.kv(indent2).with_s_key("Variable"); self.write_local(heap, stmt.variable, indent3); - self.kv(indent2).with_s_key("initial"); - self.write_expr(heap, stmt.initial, indent3); self.kv(indent2).with_s_key("Next") .with_opt_disp_val(stmt.next.as_ref().map(|v| &v.index)); } @@ -812,7 +810,6 @@ fn write_expression_parent(target: &mut String, parent: &ExpressionParent) { *target = match parent { EP::None => String::from("None"), - EP::Memory(id) => format!("MemoryStmt({})", id.0.0.index), EP::If(id) => format!("IfStmt({})", id.0.index), EP::While(id) => format!("WhileStmt({})", id.0.index), EP::Return(id) => format!("ReturnStmt({})", id.0.index), diff --git a/src/protocol/eval.rs b/src/protocol/eval.rs index 85af7bf55525596e1cc67fe667120703a96cf940..2e8a55feadb9fbcb3926b425b031b1404f450af3 100644 --- a/src/protocol/eval.rs +++ b/src/protocol/eval.rs @@ -32,6 +32,7 @@ trait ValueImpl { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum Value { + Unassigned, Input(InputValue), Output(OutputValue), Message(MessageValue), @@ -824,6 +825,7 @@ impl From<&Value> for i64 { impl ValueImpl for Value { fn exact_type(&self) -> Type { match self { + Value::Unassigned => Type::UNASSIGNED, Value::Input(val) => val.exact_type(), Value::Output(val) => val.exact_type(), Value::Message(val) => val.exact_type(), @@ -844,6 +846,7 @@ impl ValueImpl for Value { } fn is_type_compatible(&self, h: &Heap, t: &ParserType) -> bool { match self { + Value::Unassigned => true, Value::Input(_) => InputValue::is_type_compatible_hack(h, t), Value::Output(_) => OutputValue::is_type_compatible_hack(h, t), Value::Message(_) => MessageValue::is_type_compatible_hack(h, t), @@ -869,6 +872,7 @@ impl Display for Value { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let disp: &dyn Display; match self { + Value::Unassigned => disp = &Type::UNASSIGNED, Value::Input(val) => disp = val, Value::Output(val) => disp = val, Value::Message(val) => disp = val, @@ -1594,10 +1598,8 @@ impl Prompt { Statement::Local(stmt) => { match stmt { LocalStatement::Memory(stmt) => { - // Evaluate initial expression - let value = self.store.eval(h, ctx, stmt.initial)?; // Update store - self.store.initialize(h, stmt.variable.upcast(), value); + self.store.initialize(h, stmt.variable.upcast(), Value::Unassigned); } LocalStatement::Channel(stmt) => { let [from, to] = ctx.new_channel(); diff --git a/src/protocol/lexer.rs b/src/protocol/lexer.rs index 38ee597ee880bb951f22245d4b65d4523ce0e656..4153a1a50a4698435b37f7215eae2581909d3d82 100644 --- a/src/protocol/lexer.rs +++ b/src/protocol/lexer.rs @@ -655,7 +655,6 @@ impl Lexer<'_> { /// present then an empty vector will be returned. fn consume_polymorphic_vars(&mut self) -> Result, ParseError2> { let backup_pos = self.source.pos(); - self.consume_whitespace(false)?; if let Some(b'<') = self.source.next() { // Found the opening delimiter, we want at least one polyvar self.source.consume(); @@ -1635,7 +1634,11 @@ impl Lexer<'_> { self.consume_string(b"{")?; self.consume_whitespace(false)?; while self.has_local_statement() { - statements.push(self.consume_local_statement(h)?.upcast()); + let (local_id, stmt_id) = self.consume_local_statement(h)?; + statements.push(local_id.upcast()); + if let Some(stmt_id) = stmt_id { + statements.push(stmt_id.upcast()); + } self.consume_whitespace(false)?; } while !self.has_string(b"}") { @@ -1658,11 +1661,13 @@ impl Lexer<'_> { .upcast()) } } - fn consume_local_statement(&mut self, h: &mut Heap) -> Result { + fn consume_local_statement(&mut self, h: &mut Heap) -> Result<(LocalStatementId, Option), ParseError2> { if self.has_keyword(b"channel") { - Ok(self.consume_channel_statement(h)?.upcast()) + let local_id = self.consume_channel_statement(h)?.upcast(); + Ok((local_id, None)) } else { - Ok(self.consume_memory_statement(h)?.upcast()) + let (memory_id, stmt_id) = self.consume_memory_statement(h)?; + Ok((memory_id.upcast(), Some(stmt_id))) } } fn consume_channel_statement( @@ -1728,12 +1733,13 @@ impl Lexer<'_> { next: None, })) } - fn consume_memory_statement(&mut self, h: &mut Heap) -> Result { + fn consume_memory_statement(&mut self, h: &mut Heap) -> Result<(MemoryStatementId, ExpressionStatementId), ParseError2> { let position = self.source.pos(); let parser_type = self.consume_type2(h, true)?; self.consume_whitespace(true)?; let identifier = self.consume_identifier()?; self.consume_whitespace(false)?; + let assignment_position = self.source.pos(); self.consume_string(b"=")?; self.consume_whitespace(false)?; let initial = self.consume_expression(h)?; @@ -1741,18 +1747,47 @@ impl Lexer<'_> { this, position, parser_type, - identifier, + identifier: identifier.clone(), relative_pos_in_block: 0 }); self.consume_whitespace(false)?; self.consume_string(b";")?; - Ok(h.alloc_memory_statement(|this| MemoryStatement { + + // Transform into the variable declaration, followed by an assignment + let memory_stmt_id = h.alloc_memory_statement(|this| MemoryStatement { this, position, variable, - initial, next: None, - })) + }); + let variable_expr_id = h.alloc_variable_expression(|this| VariableExpression{ + this, + position: identifier.position.clone(), + identifier: NamespacedIdentifier { + position: identifier.position.clone(), + num_namespaces: 1, + value: identifier.value.clone(), + }, + declaration: None, + parent: ExpressionParent::None, + concrete_type: Default::default() + }); + let assignment_expr_id = h.alloc_assignment_expression(|this| AssignmentExpression{ + this, + position: assignment_position, + left: variable_expr_id.upcast(), + operation: AssignmentOperator::Set, + right: initial, + parent: ExpressionParent::None, + concrete_type: Default::default() + }); + let assignment_stmt_id = h.alloc_expression_statement(|this| ExpressionStatement{ + this, + position, + expression: assignment_expr_id.upcast(), + next: None + }); + Ok((memory_stmt_id, assignment_stmt_id)) } fn consume_labeled_statement( &mut self, @@ -1965,6 +2000,7 @@ impl Lexer<'_> { self.consume_keyword(b"struct")?; self.consume_whitespace(true)?; let struct_ident = self.consume_identifier()?; + self.consume_whitespace(false)?; let poly_vars = self.consume_polymorphic_vars()?; self.consume_whitespace(false)?; @@ -2023,6 +2059,7 @@ impl Lexer<'_> { self.consume_keyword(b"enum")?; self.consume_whitespace(true)?; let enum_ident = self.consume_identifier()?; + self.consume_whitespace(false)?; let poly_vars = self.consume_polymorphic_vars()?; self.consume_whitespace(false)?; @@ -2117,6 +2154,7 @@ impl Lexer<'_> { self.consume_keyword(b"composite")?; self.consume_whitespace(true)?; let identifier = self.consume_identifier()?; + self.consume_whitespace(false)?; let poly_vars = self.consume_polymorphic_vars()?; self.consume_whitespace(false)?; @@ -2143,6 +2181,7 @@ impl Lexer<'_> { self.consume_keyword(b"primitive")?; self.consume_whitespace(true)?; let identifier = self.consume_identifier()?; + self.consume_whitespace(false)?; let poly_vars = self.consume_polymorphic_vars()?; self.consume_whitespace(false)?; @@ -2169,6 +2208,7 @@ impl Lexer<'_> { let return_type = self.consume_type2(h, false)?; self.consume_whitespace(true)?; let identifier = self.consume_identifier()?; + self.consume_whitespace(false)?; let poly_vars = self.consume_polymorphic_vars()?; self.consume_whitespace(false)?; diff --git a/src/protocol/parser/depth_visitor.rs b/src/protocol/parser/depth_visitor.rs index da957edf9eb4611fd23a050d6d1f30287e99a8c9..69ae0899ead16d5fd895820d6dfac8716ef10d5f 100644 --- a/src/protocol/parser/depth_visitor.rs +++ b/src/protocol/parser/depth_visitor.rs @@ -56,7 +56,7 @@ pub(crate) trait Visitor: Sized { recursive_local_statement(self, h, stmt) } fn visit_memory_statement(&mut self, h: &mut Heap, stmt: MemoryStatementId) -> VisitorResult { - recursive_memory_statement(self, h, stmt) + Ok(()) } fn visit_channel_statement( &mut self, @@ -349,14 +349,6 @@ fn recursive_local_statement( } } -fn recursive_memory_statement( - this: &mut T, - h: &mut Heap, - stmt: MemoryStatementId, -) -> VisitorResult { - this.visit_expression(h, h[stmt].initial) -} - fn recursive_labeled_statement( this: &mut T, h: &mut Heap, diff --git a/src/protocol/parser/type_resolver.rs b/src/protocol/parser/type_resolver.rs index 286ab594464fe9c987748e0070279969b5839158..349043750ccdfadd761ee0dbb1704c0426b5b92e 100644 --- a/src/protocol/parser/type_resolver.rs +++ b/src/protocol/parser/type_resolver.rs @@ -5,6 +5,26 @@ /// TODO: Needs an optimization pass /// TODO: Needs a cleanup pass +macro_rules! enabled_debug_print { + (false, $name:literal, $format:literal) => {}; + (false, $name:literal, $format:literal, $($args:expr),*) => {}; + (true, $name:literal, $format:literal) => { + println!("[{}] {}", $name, $format) + }; + (true, $name:literal, $format:literal, $($args:expr),*) => { + println!("[{}] {}", $name, format!($format, $($args),*)) + }; +} + +macro_rules! debug_log { + ($format:literal) => { + enabled_debug_print!(true, "types", $format); + }; + ($format:literal, $($args:expr),*) => { + enabled_debug_print!(true, "types", $format, $($args),*); + }; +} + use std::collections::{HashMap, HashSet, VecDeque}; use crate::protocol::ast::*; @@ -837,6 +857,9 @@ impl TypeResolvingVisitor { ) -> VisitorResult { // Visit the definition debug_assert_eq!(ctx.module.root_id, element.root_id); + self.reset(); + self.poly_vars.clear(); + self.poly_vars.extend(element.monomorph_types.iter().cloned()); self.visit_definition(ctx, element.definition_id)?; // Keep resolving types @@ -860,12 +883,15 @@ impl Visitor2 for TypeResolvingVisitor { // Definitions fn visit_component_definition(&mut self, ctx: &mut Ctx, id: ComponentId) -> VisitorResult { - self.reset(); self.definition_type = DefinitionType::Component(id); let comp_def = &ctx.heap[id]; debug_assert_eq!(comp_def.poly_vars.len(), self.poly_vars.len(), "component polyvars do not match imposed polyvars"); + debug_log!("{}", "-".repeat(80)); + debug_log!("Visiting component '{}': {}", &String::from_utf8_lossy(&comp_def.identifier.value), id.0.index); + debug_log!("{}", "-".repeat(80)); + for param_id in comp_def.parameters.clone() { let param = &ctx.heap[param_id]; let var_type = self.determine_inference_type_from_parser_type(ctx, param.parser_type, true); @@ -878,12 +904,15 @@ impl Visitor2 for TypeResolvingVisitor { } fn visit_function_definition(&mut self, ctx: &mut Ctx, id: FunctionId) -> VisitorResult { - self.reset(); self.definition_type = DefinitionType::Function(id); let func_def = &ctx.heap[id]; debug_assert_eq!(func_def.poly_vars.len(), self.poly_vars.len(), "function polyvars do not match imposed polyvars"); + debug_log!("{}", "-".repeat(80)); + debug_log!("Visiting function '{}': {}", &String::from_utf8_lossy(&func_def.identifier.value), id.0.index); + debug_log!("{}", "-".repeat(80)); + for param_id in func_def.parameters.clone() { let param = &ctx.heap[param_id]; let var_type = self.determine_inference_type_from_parser_type(ctx, param.parser_type, true); @@ -915,9 +944,6 @@ impl Visitor2 for TypeResolvingVisitor { let var_type = self.determine_inference_type_from_parser_type(ctx, local.parser_type, true); self.var_types.insert(memory_stmt.variable.upcast(), VarData{ var_type, used_at: Vec::new() }); - let expr_id = memory_stmt.initial; - self.visit_expr(ctx, expr_id)?; - Ok(()) } @@ -1185,7 +1211,6 @@ macro_rules! debug_assert_ptrs_distinct { impl TypeResolvingVisitor { fn resolve_types(&mut self, ctx: &mut Ctx, queue: &mut ResolveQueue) -> Result<(), ParseError2> { // Keep inferring until we can no longer make any progress - println!("DEBUG: Resolve queue is {:?}", &self.expr_queued); while let Some(next_expr_id) = self.expr_queued.iter().next() { let next_expr_id = *next_expr_id; self.expr_queued.remove(&next_expr_id); @@ -1195,10 +1220,6 @@ impl TypeResolvingVisitor { // Should have inferred everything for (expr_id, expr_type) in self.expr_types.iter() { if !expr_type.is_done { - let mut buffer = std::fs::File::create("type_debug.txt").unwrap(); - use crate::protocol::ast_printer::ASTWriter; - let mut w = ASTWriter::new(); - w.write_ast(&mut buffer, &ctx.heap); // TODO: Auto-inference of integerlike types let expr = &ctx.heap[*expr_id]; return Err(ParseError2::new_error( @@ -1334,6 +1355,12 @@ impl TypeResolvingVisitor { let arg1_expr_id = expr.left; let arg2_expr_id = expr.right; + debug_log!("Assignment expr '{:?}': {}", expr.operation, upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Arg1 type: {}", self.expr_types.get(&arg1_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Arg2 type: {}", self.expr_types.get(&arg2_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + let progress_base = match expr.operation { AO::Set => false, @@ -1348,6 +1375,12 @@ impl TypeResolvingVisitor { ctx, upcast_id, arg1_expr_id, arg2_expr_id, 0 )?; + debug_log!(" * After:"); + debug_log!(" - Arg1 type [{}]: {}", progress_arg1, self.expr_types.get(&arg1_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Arg2 type [{}]: {}", progress_arg2, self.expr_types.get(&arg2_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_base || progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + + if progress_base || progress_expr { self.queue_expr_parent(ctx, upcast_id); } if progress_arg1 { self.queue_expr(arg1_expr_id); } if progress_arg2 { self.queue_expr(arg2_expr_id); } @@ -1362,10 +1395,21 @@ impl TypeResolvingVisitor { let arg1_expr_id = expr.true_expression; let arg2_expr_id = expr.false_expression; + debug_log!("Conditional expr: {}", upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Arg1 type: {}", self.expr_types.get(&arg1_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Arg2 type: {}", self.expr_types.get(&arg2_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + let (progress_expr, progress_arg1, progress_arg2) = self.apply_equal3_constraint( ctx, upcast_id, arg1_expr_id, arg2_expr_id, 0 )?; + debug_log!(" * After:"); + debug_log!(" - Arg1 type [{}]: {}", progress_arg1, self.expr_types.get(&arg1_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Arg2 type [{}]: {}", progress_arg2, self.expr_types.get(&arg2_expr_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + if progress_expr { self.queue_expr_parent(ctx, upcast_id); } if progress_arg1 { self.queue_expr(arg1_expr_id); } if progress_arg2 { self.queue_expr(arg2_expr_id); } @@ -1383,6 +1427,12 @@ impl TypeResolvingVisitor { let arg1_id = expr.left; let arg2_id = expr.right; + debug_log!("Binary expr '{:?}': {}", expr.operation, upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Arg1 type: {}", self.expr_types.get(&arg1_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Arg2 type: {}", self.expr_types.get(&arg2_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + let (progress_expr, progress_arg1, progress_arg2) = match expr.operation { BO::Concatenate => { // Arguments may be arrays/slices, output is always an array @@ -1412,9 +1462,17 @@ impl TypeResolvingVisitor { (progress_base || progress_expr, progress_base || progress_arg1, progress_base || progress_arg2) }, - BO::Equality | BO::Inequality | BO::LessThan | BO::GreaterThan | BO::LessThanEqual | BO::GreaterThanEqual => { + BO::Equality | BO::Inequality => { // Equal2 on args, forced boolean output let progress_expr = self.apply_forced_constraint(ctx, upcast_id, &BOOL_TEMPLATE)?; + let (progress_arg1, progress_arg2) = + self.apply_equal2_constraint(ctx, upcast_id, arg1_id, 0, arg2_id, 0)?; + + (progress_expr, progress_arg1, progress_arg2) + }, + BO::LessThan | BO::GreaterThan | BO::LessThanEqual | BO::GreaterThanEqual => { + // Equal2 on args with numberlike type, forced boolean output + let progress_expr = self.apply_forced_constraint(ctx, upcast_id, &BOOL_TEMPLATE)?; let progress_arg_base = self.apply_forced_constraint(ctx, arg1_id, &NUMBERLIKE_TEMPLATE)?; let (progress_arg1, progress_arg2) = self.apply_equal2_constraint(ctx, upcast_id, arg1_id, 0, arg2_id, 0)?; @@ -1431,6 +1489,11 @@ impl TypeResolvingVisitor { }, }; + debug_log!(" * After:"); + debug_log!(" - Arg1 type [{}]: {}", progress_arg1, self.expr_types.get(&arg1_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Arg2 type [{}]: {}", progress_arg2, self.expr_types.get(&arg2_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + if progress_expr { self.queue_expr_parent(ctx, upcast_id); } if progress_arg1 { self.queue_expr(arg1_id); } if progress_arg2 { self.queue_expr(arg2_id); } @@ -1445,6 +1508,11 @@ impl TypeResolvingVisitor { let expr = &ctx.heap[id]; let arg_id = expr.expression; + debug_log!("Unary expr '{:?}': {}", expr.operation, upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Arg type: {}", self.expr_types.get(&arg_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + let (progress_expr, progress_arg) = match expr.operation { UO::Positive | UO::Negative => { // Equal types of numeric class @@ -1470,6 +1538,10 @@ impl TypeResolvingVisitor { } }; + debug_log!(" * After:"); + debug_log!(" - Arg type [{}]: {}", progress_arg, self.expr_types.get(&arg_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + if progress_expr { self.queue_expr_parent(ctx, upcast_id); } if progress_arg { self.queue_expr(arg_id); } @@ -1482,6 +1554,12 @@ impl TypeResolvingVisitor { let subject_id = expr.subject; let index_id = expr.index; + debug_log!("Indexing expr: {}", upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Subject type: {}", self.expr_types.get(&subject_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Index type: {}", self.expr_types.get(&index_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + // Make sure subject is arraylike and index is integerlike let progress_subject_base = self.apply_forced_constraint(ctx, subject_id, &ARRAYLIKE_TEMPLATE)?; let progress_index = self.apply_forced_constraint(ctx, index_id, &INTEGERLIKE_TEMPLATE)?; @@ -1490,6 +1568,11 @@ impl TypeResolvingVisitor { let (progress_expr, progress_subject) = self.apply_equal2_constraint(ctx, upcast_id, upcast_id, 0, subject_id, 1)?; + debug_log!(" * After:"); + debug_log!(" - Subject type [{}]: {}", progress_subject_base || progress_subject, self.expr_types.get(&subject_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Index type [{}]: {}", progress_index, self.expr_types.get(&index_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + if progress_expr { self.queue_expr_parent(ctx, upcast_id); } if progress_subject_base || progress_subject { self.queue_expr(subject_id); } if progress_index { self.queue_expr(index_id); } @@ -1504,6 +1587,13 @@ impl TypeResolvingVisitor { let from_id = expr.from_index; let to_id = expr.to_index; + debug_log!("Slicing expr: {}", upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Subject type: {}", self.expr_types.get(&subject_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - FromIdx type: {}", self.expr_types.get(&from_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - ToIdx type: {}", self.expr_types.get(&to_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + // Make sure subject is arraylike and indices are of equal integerlike let progress_subject_base = self.apply_forced_constraint(ctx, subject_id, &ARRAYLIKE_TEMPLATE)?; let progress_idx_base = self.apply_forced_constraint(ctx, from_id, &INTEGERLIKE_TEMPLATE)?; @@ -1513,6 +1603,13 @@ impl TypeResolvingVisitor { let (progress_expr, progress_subject) = self.apply_equal2_constraint(ctx, upcast_id, upcast_id, 0, subject_id, 1)?; + + debug_log!(" * After:"); + debug_log!(" - Subject type [{}]: {}", progress_subject_base || progress_subject, self.expr_types.get(&subject_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - FromIdx type [{}]: {}", progress_idx_base || progress_from, self.expr_types.get(&from_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - ToIdx type [{}]: {}", progress_idx_base || progress_to, self.expr_types.get(&to_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + if progress_expr { self.queue_expr_parent(ctx, upcast_id); } if progress_subject_base || progress_subject { self.queue_expr(subject_id); } if progress_idx_base || progress_from { self.queue_expr(from_id); } @@ -1526,6 +1623,11 @@ impl TypeResolvingVisitor { let expr = &ctx.heap[id]; let subject_id = expr.subject; + debug_log!("Select expr: {}", upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Subject type: {}", self.expr_types.get(&subject_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + let (progress_subject, progress_expr) = match &expr.field { Field::Length => { let progress_subject = self.apply_forced_constraint(ctx, subject_id, &ARRAYLIKE_TEMPLATE)?; @@ -1537,6 +1639,10 @@ impl TypeResolvingVisitor { } }; + debug_log!(" * After:"); + debug_log!(" - Subject type [{}]: {}", progress_subject, self.expr_types.get(&subject_id).unwrap().display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + if progress_subject { self.queue_expr(subject_id); } if progress_expr { self.queue_expr_parent(ctx, upcast_id); } @@ -1548,6 +1654,10 @@ impl TypeResolvingVisitor { let expr = &ctx.heap[id]; let expr_elements = expr.elements.clone(); // TODO: @performance + debug_log!("Array expr ({} elements): {}", expr_elements.len(), upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + // All elements should have an equal type let progress = self.apply_equal_n_constraint(ctx, upcast_id, &expr_elements)?; let mut any_progress = false; @@ -1574,6 +1684,9 @@ impl TypeResolvingVisitor { if arg_progress { self.queue_expr(upcast_id); } } + debug_log!(" * After:"); + debug_log!(" - Expr type [{}]: {}", expr_progress, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + if expr_progress { self.queue_expr_parent(ctx, upcast_id); } Ok(()) @@ -1599,11 +1712,21 @@ impl TypeResolvingVisitor { // polymorphic struct/enum/union literals. These likely follow the same // pattern as here. fn progress_call_expr(&mut self, ctx: &mut Ctx, id: CallExpressionId) -> Result<(), ParseError2> { - println!("DEBUG: Processing call {}", id.0.index); let upcast_id = id.upcast(); let expr = &ctx.heap[id]; let extra = self.extra_data.get_mut(&upcast_id).unwrap(); + debug_log!("Call expr '{}': {}", match &expr.method { + Method::Create => String::from("create"), + Method::Fires => String::from("fires"), + Method::Get => String::from("get"), + Method::Put => String::from("put"), + Method::Symbolic(method) => String::from_utf8_lossy(&method.identifier.value).to_string() + },upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + debug_log!(" * During (inferring types from arguments and return type):"); + // Check if we can make progress using the arguments and/or return types // while keeping track of the polyvars we've extended let mut poly_progress = HashSet::new(); @@ -1617,7 +1740,7 @@ impl TypeResolvingVisitor { ctx, upcast_id, signature_type, 0, argument_type, 0 )?; - println!("DEBUG Arg {}: {} <--> {}", arg_idx, signature_type.display_name(&ctx.heap), unsafe{&*argument_type}.display_name(&ctx.heap)); + debug_log!(" - Arg {} type | sig: {}, arg: {}", arg_idx, signature_type.display_name(&ctx.heap), unsafe{&*argument_type}.display_name(&ctx.heap)); if progress_sig { // Progressed signature, so also apply inference to the @@ -1632,7 +1755,8 @@ impl TypeResolvingVisitor { Ok(false) => {}, Err(()) => { poly_infer_error = true; } } - println!("DEBUG Poly {}: {} <--> {}", poly_idx, polymorph_type.display_name(&ctx.heap), InferenceType::partial_display_name(&ctx.heap, poly_section)); + + debug_log!(" - Poly {} type | sig: {}, arg: {}", poly_idx, polymorph_type.display_name(&ctx.heap), InferenceType::partial_display_name(&ctx.heap, poly_section)); } } if progress_arg { @@ -1648,7 +1772,7 @@ impl TypeResolvingVisitor { ctx, upcast_id, signature_type, 0, expr_type, 0 )?; - println!("DEBUG Ret {} <--> {}", signature_type.display_name(&ctx.heap), unsafe{&*expr_type}.display_name(&ctx.heap)); + debug_log!(" - Ret type | sig: {}, arg: {}", signature_type.display_name(&ctx.heap), unsafe{&*expr_type}.display_name(&ctx.heap)); if progress_sig { // As above: apply inference to polyargs as well @@ -1662,7 +1786,7 @@ impl TypeResolvingVisitor { Ok(false) => {}, Err(()) => { poly_infer_error = true; } } - println!("DEBUG Poly {}: {} <--> {}", poly_idx, polymorph_type.display_name(&ctx.heap), InferenceType::partial_display_name(&ctx.heap, poly_section)); + debug_log!(" - Poly {} type | sig: {}, arg: {}", poly_idx, polymorph_type.display_name(&ctx.heap), InferenceType::partial_display_name(&ctx.heap, poly_section)); } } if progress_expr { @@ -1680,6 +1804,7 @@ impl TypeResolvingVisitor { // If we did not have an error in the polymorph inference above, then // reapplying the polymorph type to each argument type and the return // type should always succeed. + debug_log!(" * During (reinferring from progress polyvars):"); // TODO: @performance If the algorithm is changed to be more "on demand // argument re-evaluation", instead of "all-argument re-evaluation", // then this is no longer true @@ -1698,7 +1823,10 @@ impl TypeResolvingVisitor { seek_idx = end_idx; } - if !modified_sig { continue; } + if !modified_sig { + debug_log!(" - Poly {} | Arg {} type | signature has not changed", poly_idx, arg_idx); + continue; + } // Part of signature was modified, so update expression used as // argument as well @@ -1708,6 +1836,7 @@ impl TypeResolvingVisitor { ctx, arg_expr_id, arg_type, 0, sig_type, 0 ).expect("no inference error at argument type"); if progress_arg { self.expr_queued.insert(arg_expr_id); } + debug_log!(" - Poly {} | Arg {} type | sig: {}, arg: {}", poly_idx, arg_idx, sig_type.display_name(&ctx.heap), unsafe{&*arg_type}.display_name(&ctx.heap)); } // Again: do the same for the return type @@ -1732,9 +1861,15 @@ impl TypeResolvingVisitor { self.expr_queued.insert(parent_id); } } + debug_log!(" - Poly {} | Ret type | sig: {}, arg: {}", poly_idx, sig_type.display_name(&ctx.heap), ret_type.display_name(&ctx.heap)); + } else { + debug_log!(" - Poly {} | Ret type | signature has not changed", poly_idx); } } + debug_log!(" * After:"); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + Ok(()) } @@ -1743,6 +1878,11 @@ impl TypeResolvingVisitor { let var_expr = &ctx.heap[id]; let var_id = var_expr.declaration.unwrap(); + debug_log!("Variable expr '{}': {}", &String::from_utf8_lossy(&ctx.heap[var_id].identifier().value), upcast_id.index); + debug_log!(" * Before:"); + debug_log!(" - Var type: {}", self.var_types.get(&var_id).unwrap().var_type.display_name(&ctx.heap)); + debug_log!(" - Expr type: {}", self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + // Retrieve shared variable type and expression type and apply inference let var_data = self.var_types.get_mut(&var_id).unwrap(); let expr_type = self.expr_types.get_mut(&upcast_id).unwrap(); @@ -1779,6 +1919,11 @@ impl TypeResolvingVisitor { } if progress_expr { self.queue_expr_parent(ctx, upcast_id); } + debug_log!(" * After:"); + debug_log!(" - Var type [{}]: {}", progress_var, self.var_types.get(&var_id).unwrap().var_type.display_name(&ctx.heap)); + debug_log!(" - Expr type [{}]: {}", progress_expr, self.expr_types.get(&upcast_id).unwrap().display_name(&ctx.heap)); + + Ok(()) } @@ -1996,7 +2141,7 @@ impl TypeResolvingVisitor { EP::None => // Should have been set by linker unreachable!(), - EP::Memory(_) | EP::ExpressionStmt(_) | EP::Expression(_, _) => + EP::ExpressionStmt(_) | EP::Expression(_, _) => // Determined during type inference InferenceType::new(false, false, vec![ITP::Unknown]), EP::If(_) | EP::While(_) | EP::Assert(_) => @@ -2055,7 +2200,6 @@ impl TypeResolvingVisitor { // map them back and forth to the polymorphic arguments of the function // we are calling. let call = &ctx.heap[call_id]; - debug_assert!(!call.poly_args.is_empty()); // Handle the polymorphic variables themselves let mut poly_vars = Vec::with_capacity(call.poly_args.len()); diff --git a/src/protocol/parser/visitor_linker.rs b/src/protocol/parser/visitor_linker.rs index d230550a16d658bae1e3d4a02538bc21f88bcd92..bcfeab5ab112973f56804bab31e89cc0b2933318 100644 --- a/src/protocol/parser/visitor_linker.rs +++ b/src/protocol/parser/visitor_linker.rs @@ -220,9 +220,6 @@ impl Visitor2 for ValidityAndLinkerVisitor { self.visit_parser_type(ctx, parser_type_id)?; debug_assert_eq!(self.expr_parent, ExpressionParent::None); - self.expr_parent = ExpressionParent::Memory(id); - self.visit_expr(ctx, ctx.heap[id].initial)?; - self.expr_parent = ExpressionParent::None; } Ok(()) diff --git a/src/runtime/tests.rs b/src/runtime/tests.rs index 7d6ae12b435c1331daee790ba951677275e52ebb..052b3e04d4d9ef84c1aa8f87460e85a65c30df91 100644 --- a/src/runtime/tests.rs +++ b/src/runtime/tests.rs @@ -1397,7 +1397,7 @@ fn eq_no_causality() { } } } - T some_function(msg a, msg b) { + T some_function(int a, int b) { T something = a; return something; }