diff --git a/src/protocol/ast.rs b/src/protocol/ast.rs index cf9eedd0b0a2244d5a9ddd0e6f3525c5248efa92..ac14cd4da6bc831eaa42b9634a9685e8e0df4e7c 100644 --- a/src/protocol/ast.rs +++ b/src/protocol/ast.rs @@ -1224,22 +1224,44 @@ impl Expression { } } - pub fn span(&self) -> InputSpan { + /// Returns operator span, function name, a binding's "let" span, etc. An + /// indicator for the kind of expression that is being applied. + pub fn operation_span(&self) -> InputSpan { + match self { + Expression::Assignment(expr) => expr.operator_span, + Expression::Binding(expr) => expr.operator_span, + Expression::Conditional(expr) => expr.operator_span, + Expression::Binary(expr) => expr.operator_span, + Expression::Unary(expr) => expr.operator_span, + Expression::Indexing(expr) => expr.operator_span, + Expression::Slicing(expr) => expr.slicing_span, + Expression::Select(expr) => expr.operator_span, + Expression::Literal(expr) => expr.span, + Expression::Cast(expr) => expr.cast_span, + Expression::Call(expr) => expr.func_span, + Expression::Variable(expr) => expr.identifier.span, + } + } + + /// Returns the span covering the entire expression (i.e. including the + /// spans of the arguments as well). + pub fn full_span(&self) -> InputSpan { match self { - Expression::Assignment(expr) => expr.span, - Expression::Binding(expr) => expr.span, - Expression::Conditional(expr) => expr.span, - Expression::Binary(expr) => expr.span, - Expression::Unary(expr) => expr.span, - Expression::Indexing(expr) => expr.span, - Expression::Slicing(expr) => expr.span, - Expression::Select(expr) => expr.span, + Expression::Assignment(expr) => expr.full_span, + Expression::Binding(expr) => expr.full_span, + Expression::Conditional(expr) => expr.full_span, + Expression::Binary(expr) => expr.full_span, + Expression::Unary(expr) => expr.full_span, + Expression::Indexing(expr) => expr.full_span, + Expression::Slicing(expr) => expr.full_span, + Expression::Select(expr) => expr.full_span, Expression::Literal(expr) => expr.span, - Expression::Cast(expr) => expr.span, - Expression::Call(expr) => expr.span, + Expression::Cast(expr) => expr.full_span, + Expression::Call(expr) => expr.full_span, Expression::Variable(expr) => expr.identifier.span, } } + // TODO: @cleanup pub fn parent(&self) -> &ExpressionParent { match self { @@ -1304,7 +1326,8 @@ pub enum AssignmentOperator { pub struct AssignmentExpression { pub this: AssignmentExpressionId, // Parsing - pub span: InputSpan, // of the operator + pub operator_span: InputSpan, + pub full_span: InputSpan, pub left: ExpressionId, pub operation: AssignmentOperator, pub right: ExpressionId, @@ -1317,7 +1340,8 @@ pub struct AssignmentExpression { pub struct BindingExpression { pub this: BindingExpressionId, // Parsing - pub span: InputSpan, // of the binding keyword + pub operator_span: InputSpan, + pub full_span: InputSpan, pub bound_to: ExpressionId, pub bound_from: ExpressionId, // Validator/Linker @@ -1329,7 +1353,8 @@ pub struct BindingExpression { pub struct ConditionalExpression { pub this: ConditionalExpressionId, // Parsing - pub span: InputSpan, // of question mark operator + pub operator_span: InputSpan, + pub full_span: InputSpan, pub test: ExpressionId, pub true_expression: ExpressionId, pub false_expression: ExpressionId, @@ -1365,7 +1390,8 @@ pub enum BinaryOperator { pub struct BinaryExpression { pub this: BinaryExpressionId, // Parsing - pub span: InputSpan, // of the operator + pub operator_span: InputSpan, + pub full_span: InputSpan, pub left: ExpressionId, pub operation: BinaryOperator, pub right: ExpressionId, @@ -1386,7 +1412,8 @@ pub enum UnaryOperator { pub struct UnaryExpression { pub this: UnaryExpressionId, // Parsing - pub span: InputSpan, // of the operator + pub operator_span: InputSpan, + pub full_span: InputSpan, pub operation: UnaryOperator, pub expression: ExpressionId, // Validator/Linker @@ -1398,7 +1425,8 @@ pub struct UnaryExpression { pub struct IndexingExpression { pub this: IndexingExpressionId, // Parsing - pub span: InputSpan, + pub operator_span: InputSpan, + pub full_span: InputSpan, pub subject: ExpressionId, pub index: ExpressionId, // Validator/Linker @@ -1410,7 +1438,8 @@ pub struct IndexingExpression { pub struct SlicingExpression { pub this: SlicingExpressionId, // Parsing - pub span: InputSpan, // from '[' to ']'; + pub slicing_span: InputSpan, // from '[' to ']' + pub full_span: InputSpan, // includes subject pub subject: ExpressionId, pub from_index: ExpressionId, pub to_index: ExpressionId, @@ -1423,7 +1452,8 @@ pub struct SlicingExpression { pub struct SelectExpression { pub this: SelectExpressionId, // Parsing - pub span: InputSpan, // of the '.' + pub operator_span: InputSpan, // of the '.' + pub full_span: InputSpan, // includes subject and field pub subject: ExpressionId, pub field_name: Identifier, // Validator/Linker @@ -1435,7 +1465,8 @@ pub struct SelectExpression { pub struct CastExpression { pub this: CastExpressionId, // Parsing - pub span: InputSpan, // of the "cast" keyword, + pub cast_span: InputSpan, // of the "cast" keyword, + pub full_span: InputSpan, // includes the cast subject pub to_type: ParserType, pub subject: ExpressionId, // Validator/linker @@ -1447,7 +1478,8 @@ pub struct CastExpression { pub struct CallExpression { pub this: CallExpressionId, // Parsing - pub span: InputSpan, + pub func_span: InputSpan, // of the function name + pub full_span: InputSpan, // includes the arguments and parentheses pub parser_type: ParserType, // of the function call, not the return type pub method: Method, pub arguments: Vec, diff --git a/src/protocol/eval/error.rs b/src/protocol/eval/error.rs index f2f91e0838e03731c64a3f4b782cea88fff6dc20..fc194bb37c8ef31e8084d2613f4cdb9b9a36a344 100644 --- a/src/protocol/eval/error.rs +++ b/src/protocol/eval/error.rs @@ -81,7 +81,7 @@ impl EvalError { let expr = &heap[expr_id]; let statements = vec![ - ErrorStatement::from_source_at_span(StatementKind::Error, last_module_source, expr.span(), msg) + ErrorStatement::from_source_at_span(StatementKind::Error, last_module_source, expr.full_span(), msg) ]; EvalError{ statements, frames } diff --git a/src/protocol/eval/executor.rs b/src/protocol/eval/executor.rs index 3f2a19ea3aee42b7afbd63a876e059320273a491..e7bb604b13a60c3d851918811cc9ae566d8686bb 100644 --- a/src/protocol/eval/executor.rs +++ b/src/protocol/eval/executor.rs @@ -587,6 +587,16 @@ impl Prompt { let msg_value = cur_frame.expr_values.pop_front().unwrap(); let deref_msg_value = self.store.maybe_read_ref(&msg_value).clone(); + match deref_msg_value { + Value::Message(_) => {}, + _ => { + return Err(EvalError::new_error_at_expr( + self, modules, heap, expr_id, + String::from("Calls to `put` are currently restricted to only send instances of `msg` types. This will change in the future") + )); + } + } + if ctx.did_put(deref_port_value.clone()) { // We're fine, deallocate in case the expression value stack // held an owned value diff --git a/src/protocol/parser/pass_definitions.rs b/src/protocol/parser/pass_definitions.rs index 5a9ce7f52fd1db5c5e161964a2e492249f0d8e68..2fe843f6a6a6c434b3a374966a6c6f2620dc0766 100644 --- a/src/protocol/parser/pass_definitions.rs +++ b/src/protocol/parser/pass_definitions.rs @@ -861,7 +861,8 @@ impl PassDefinitions { }); let assignment_expr_id = ctx.heap.alloc_assignment_expression(|this| AssignmentExpression{ this, - span: assign_span, + operator_span: assign_span, + full_span: InputSpan::from_positions(memory_span.begin, initial_expr_end_pos), left: variable_expr_id.upcast(), operation: AssignmentOperator::Set, right: initial_expr_id, @@ -944,14 +945,19 @@ impl PassDefinitions { let expr = self.consume_conditional_expression(module, iter, ctx)?; if let Some(operation) = parse_assignment_operator(iter.next()) { - let span = iter.next_span(); + let operator_span = iter.next_span(); iter.consume(); let left = expr; let right = self.consume_expression(module, iter, ctx)?; + let full_span = InputSpan::from_positions( + ctx.heap[left].full_span().begin, + ctx.heap[right].full_span().end, + ); + Ok(ctx.heap.alloc_assignment_expression(|this| AssignmentExpression{ - this, span, left, operation, right, + this, operator_span, full_span, left, operation, right, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast()) @@ -965,15 +971,21 @@ impl PassDefinitions { ) -> Result { let result = self.consume_concat_expression(module, iter, ctx)?; if let Some(TokenKind::Question) = iter.next() { - let span = iter.next_span(); + let operator_span = iter.next_span(); iter.consume(); let test = result; let true_expression = self.consume_expression(module, iter, ctx)?; consume_token(&module.source, iter, TokenKind::Colon)?; let false_expression = self.consume_expression(module, iter, ctx)?; + + let full_span = InputSpan::from_positions( + ctx.heap[test].full_span().begin, + ctx.heap[false_expression].full_span().end, + ); + Ok(ctx.heap.alloc_conditional_expression(|this| ConditionalExpression{ - this, span, test, true_expression, false_expression, + this, operator_span, full_span, test, true_expression, false_expression, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast()) @@ -1150,15 +1162,15 @@ impl PassDefinitions { let next = iter.next(); if let Some(operation) = parse_prefix_token(next) { - let span = iter.next_span(); + let operator_span = iter.next_span(); iter.consume(); let expression = self.consume_prefix_expression(module, iter, ctx)?; + let full_span = InputSpan::from_positions( + operator_span.begin, ctx.heap[expression].full_span().end, + ); Ok(ctx.heap.alloc_unary_expression(|this| UnaryExpression { - this, - span, - operation, - expression, + this, operator_span, full_span, operation, expression, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast()) @@ -1192,16 +1204,16 @@ impl PassDefinitions { let mut next = iter.next(); while has_matching_postfix_token(next) { let token = next.unwrap(); - let mut span = iter.next_span(); + let mut operator_span = iter.next_span(); iter.consume(); if token == TokenKind::PlusPlus { return Err(ParseError::new_error_str_at_span( - &module.source, span, "postfix increment is not supported in this language" + &module.source, operator_span, "postfix increment is not supported in this language" )); } else if token == TokenKind::MinusMinus { return Err(ParseError::new_error_str_at_span( - &module.source, span, "prefix increment is not supported in this language" + &module.source, operator_span, "prefix increment is not supported in this language" )); } else if token == TokenKind::OpenSquare { let subject = result; @@ -1214,19 +1226,28 @@ impl PassDefinitions { let to_index = self.consume_expression(module, iter, ctx)?; let end_span = consume_token(&module.source, iter, TokenKind::CloseSquare)?; - span.end = end_span.end; + operator_span.end = end_span.end; + let full_span = InputSpan::from_positions( + ctx.heap[subject].full_span().begin, operator_span.end + ); result = ctx.heap.alloc_slicing_expression(|this| SlicingExpression{ - this, span, subject, from_index, to_index, + this, + slicing_span: operator_span, + full_span, subject, from_index, to_index, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast(); } else if Some(TokenKind::CloseSquare) == next { let end_span = consume_token(&module.source, iter, TokenKind::CloseSquare)?; - span.end = end_span.end; + operator_span.end = end_span.end; + + let full_span = InputSpan::from_positions( + ctx.heap[subject].full_span().begin, operator_span.end + ); result = ctx.heap.alloc_indexing_expression(|this| IndexingExpression{ - this, span, subject, + this, operator_span, full_span, subject, index: from_index, parent: ExpressionParent::None, unique_id_in_definition: -1, @@ -1241,8 +1262,11 @@ impl PassDefinitions { let subject = result; let field_name = consume_ident_interned(&module.source, iter, ctx)?; + let full_span = InputSpan::from_positions( + ctx.heap[subject].full_span().begin, field_name.span.end + ); result = ctx.heap.alloc_select_expression(|this| SelectExpression{ - this, span, subject, field_name, + this, operator_span, full_span, subject, field_name, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast(); @@ -1408,11 +1432,14 @@ impl PassDefinitions { }, Definition::Component(_) => { // Component instantiation - let arguments = self.consume_expression_list(module, iter, ctx, None)?; + let func_span = parser_type.full_span; + let mut full_span = func_span; + let arguments = self.consume_expression_list( + module, iter, ctx, Some(&mut full_span.end) + )?; ctx.heap.alloc_call_expression(|this| CallExpression{ - this, - span: parser_type.full_span, + this, func_span, full_span, parser_type, method: Method::UserComponent, arguments, @@ -1438,14 +1465,14 @@ impl PassDefinitions { }; // Function call: consume the arguments - let arguments = self.consume_expression_list(module, iter, ctx, None)?; + let func_span = parser_type.full_span; + let mut full_span = func_span; + let arguments = self.consume_expression_list( + module, iter, ctx, Some(&mut full_span.end) + )?; ctx.heap.alloc_call_expression(|this| CallExpression{ - this, - span: parser_type.full_span, - parser_type, - method, - arguments, + this, func_span, full_span, parser_type, method, arguments, definition: target_definition_id, parent: ExpressionParent::None, unique_id_in_definition: -1, @@ -1481,18 +1508,19 @@ impl PassDefinitions { }).upcast() } else if ident_text == KW_LET { // Binding expression - let keyword_span = iter.next_span(); + let operator_span = iter.next_span(); iter.consume(); let bound_to = self.consume_prefix_expression(module, iter, ctx)?; consume_token(&module.source, iter, TokenKind::Equal)?; let bound_from = self.consume_prefix_expression(module, iter, ctx)?; + let full_span = InputSpan::from_positions( + operator_span.begin, ctx.heap[bound_from].full_span().end, + ); + ctx.heap.alloc_binding_expression(|this| BindingExpression{ - this, - span: keyword_span, - bound_to, - bound_from, + this, operator_span, full_span, bound_to, bound_from, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast() @@ -1521,13 +1549,14 @@ impl PassDefinitions { consume_token(&module.source, iter, TokenKind::OpenParen)?; let subject = self.consume_expression(module, iter, ctx)?; + let mut full_span = iter.next_span(); + full_span.begin = to_type.full_span.begin; consume_token(&module.source, iter, TokenKind::CloseParen)?; ctx.heap.alloc_cast_expression(|this| CastExpression{ this, - span: ident_span, - to_type, - subject, + cast_span: to_type.full_span, + full_span, to_type, subject, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast() @@ -1590,14 +1619,19 @@ impl PassDefinitions { ) -> Result { let mut result = higher_precedence_fn(self, module, iter, ctx)?; while let Some(operation) = match_fn(iter.next()) { - let span = iter.next_span(); + let operator_span = iter.next_span(); iter.consume(); let left = result; let right = higher_precedence_fn(self, module, iter, ctx)?; + let full_span = InputSpan::from_positions( + ctx.heap[left].full_span().begin, + ctx.heap[right].full_span().end, + ); + result = ctx.heap.alloc_binary_expression(|this| BinaryExpression{ - this, span, left, operation, right, + this, operator_span, full_span, left, operation, right, parent: ExpressionParent::None, unique_id_in_definition: -1, }).upcast(); diff --git a/src/protocol/parser/pass_typing.rs b/src/protocol/parser/pass_typing.rs index 9491debeac0ded842480407e0838f6966261a762..31722de056958fcd0a78b60194df36515108eab5 100644 --- a/src/protocol/parser/pass_typing.rs +++ b/src/protocol/parser/pass_typing.rs @@ -1429,7 +1429,7 @@ impl PassTyping { }; let poly_vars = ctx.heap[definition].poly_vars(); return Err(ParseError::new_error_at_span( - &ctx.module.source, expr.span(), format!( + &ctx.module.source, expr.operation_span(), format!( "could not fully infer the type of polymorphic variable '{}' of this expression (got '{}')", poly_vars[poly_idx].value.as_str(), poly_type.display_name(&ctx.heap) ) @@ -1456,7 +1456,7 @@ impl PassTyping { } else { let expr = &ctx.heap[infer_expr.expr_id]; return Err(ParseError::new_error_at_span( - &ctx.module.source, expr.span(), format!( + &ctx.module.source, expr.full_span(), format!( "could not fully infer the type of this expression (got '{}')", expr_type.display_name(&ctx.heap) ) @@ -2439,10 +2439,10 @@ impl PassTyping { let cast_expr = &ctx.heap[id]; let subject_expr = &ctx.heap[cast_expr.subject]; return Err(ParseError::new_error_str_at_span( - &ctx.module.source, cast_expr.span, "invalid casting operation" + &ctx.module.source, cast_expr.full_span, "invalid casting operation" ).with_info_at_span( - &ctx.module.source, subject_expr.span(), format!( - "cannot cast this type '{}' to the cast type '{}'", + &ctx.module.source, subject_expr.full_span(), format!( + "cannot cast the argument type '{}' to the cast type '{}'", subject_type.display_name(&ctx.heap), expr_type.display_name(&ctx.heap) ) @@ -2781,9 +2781,9 @@ impl PassTyping { if infer_res == DualInferenceResult::Incompatible { // TODO: Check if I still need to use this - let outer_span = ctx.heap[outer_expr_id].span(); + let outer_span = ctx.heap[outer_expr_id].full_span(); let (span_name, span) = match expr_id { - Some(expr_id) => ("argument's", ctx.heap[expr_id].span()), + Some(expr_id) => ("argument's", ctx.heap[expr_id].full_span()), None => ("type's", outer_span) }; let (signature_display_type, expression_display_type) = unsafe { ( @@ -3468,12 +3468,12 @@ impl PassTyping { let arg_type = &self.expr_types[arg_expr_idx as usize].expr_type; return ParseError::new_error_at_span( - &ctx.module.source, expr.span(), format!( + &ctx.module.source, expr.operation_span(), format!( "incompatible types: this expression expected a '{}'", expr_type.display_name(&ctx.heap) ) ).with_info_at_span( - &ctx.module.source, arg_expr.span(), format!( + &ctx.module.source, arg_expr.full_span(), format!( "but this expression yields a '{}'", arg_type.display_name(&ctx.heap) ) @@ -3494,15 +3494,15 @@ impl PassTyping { let arg2_type = &self.expr_types[arg2_idx as usize].expr_type; return ParseError::new_error_str_at_span( - &ctx.module.source, expr.span(), + &ctx.module.source, expr.operation_span(), "incompatible types: cannot apply this expression" ).with_info_at_span( - &ctx.module.source, arg1.span(), format!( + &ctx.module.source, arg1.full_span(), format!( "Because this expression has type '{}'", arg1_type.display_name(&ctx.heap) ) ).with_info_at_span( - &ctx.module.source, arg2.span(), format!( + &ctx.module.source, arg2.full_span(), format!( "But this expression has type '{}'", arg2_type.display_name(&ctx.heap) ) @@ -3517,7 +3517,7 @@ impl PassTyping { let expr_type = &self.expr_types[expr_idx as usize].expr_type; return ParseError::new_error_at_span( - &ctx.module.source, expr.span(), format!( + &ctx.module.source, expr.full_span(), format!( "incompatible types: got a '{}' but expected a '{}'", expr_type.display_name(&ctx.heap), InferenceType::partial_display_name(&ctx.heap, template) @@ -3593,7 +3593,7 @@ impl PassTyping { Expression::Call(expr) => { let (poly_var, func_name) = get_poly_var_and_definition_name(ctx, poly_var_idx, poly_data.definition_id); return ParseError::new_error_at_span( - &ctx.module.source, expr.span, format!( + &ctx.module.source, expr.func_span, format!( "Conflicting type for polymorphic variable '{}' of '{}'", poly_var, func_name ) @@ -3611,7 +3611,7 @@ impl PassTyping { Expression::Select(expr) => { let (poly_var, struct_name) = get_poly_var_and_definition_name(ctx, poly_var_idx, poly_data.definition_id); return ParseError::new_error_at_span( - &ctx.module.source, expr.span, format!( + &ctx.module.source, expr.full_span, format!( "Conflicting type for polymorphic variable '{}' while accessing field '{}' of '{}'", poly_var, expr.field_name.value.as_str(), struct_name ) @@ -3657,7 +3657,7 @@ impl PassTyping { ) { return construct_main_error(ctx, poly_data, poly_idx, expr) .with_info_at_span( - &ctx.module.source, expr.span(), format!( + &ctx.module.source, expr.full_span(), format!( "The {} inferred the conflicting types '{}' and '{}'", expr_return_name, InferenceType::partial_display_name(&ctx.heap, section_a), @@ -3679,7 +3679,7 @@ impl PassTyping { // Same argument let arg = &ctx.heap[expr_args[arg_a_idx]]; return error.with_info_at_span( - &ctx.module.source, arg.span(), format!( + &ctx.module.source, arg.full_span(), format!( "This argument inferred the conflicting types '{}' and '{}'", InferenceType::partial_display_name(&ctx.heap, section_a), InferenceType::partial_display_name(&ctx.heap, section_b) @@ -3689,12 +3689,12 @@ impl PassTyping { let arg_a = &ctx.heap[expr_args[arg_a_idx]]; let arg_b = &ctx.heap[expr_args[arg_b_idx]]; return error.with_info_at_span( - &ctx.module.source, arg_a.span(), format!( + &ctx.module.source, arg_a.full_span(), format!( "This argument inferred it to '{}'", InferenceType::partial_display_name(&ctx.heap, section_a) ) ).with_info_at_span( - &ctx.module.source, arg_b.span(), format!( + &ctx.module.source, arg_b.full_span(), format!( "While this argument inferred it to '{}'", InferenceType::partial_display_name(&ctx.heap, section_b) ) @@ -3708,13 +3708,13 @@ impl PassTyping { let arg = &ctx.heap[expr_args[arg_a_idx]]; return construct_main_error(ctx, poly_data, poly_idx, expr) .with_info_at_span( - &ctx.module.source, arg.span(), format!( + &ctx.module.source, arg.full_span(), format!( "This argument inferred it to '{}'", InferenceType::partial_display_name(&ctx.heap, section_arg) ) ) .with_info_at_span( - &ctx.module.source, expr.span(), format!( + &ctx.module.source, expr.full_span(), format!( "While the {} inferred it to '{}'", expr_return_name, InferenceType::partial_display_name(&ctx.heap, section_ret) @@ -3730,7 +3730,7 @@ impl PassTyping { let arg = &ctx.heap[expr_args[arg_idx]]; return construct_main_error(ctx, poly_data, poly_idx, expr) .with_info_at_span( - &ctx.module.source, arg.span(), format!( + &ctx.module.source, arg.full_span(), format!( "The polymorphic variable has type '{}' (which might have been partially inferred) while the argument inferred it to '{}'", InferenceType::partial_display_name(&ctx.heap, poly_section), InferenceType::partial_display_name(&ctx.heap, arg_section) @@ -3742,7 +3742,7 @@ impl PassTyping { if let Some((poly_idx, poly_section, ret_section)) = has_explicit_poly_mismatch(&poly_data.poly_vars, &poly_data.returned) { return construct_main_error(ctx, poly_data, poly_idx, expr) .with_info_at_span( - &ctx.module.source, expr.span(), format!( + &ctx.module.source, expr.full_span(), format!( "The polymorphic variable has type '{}' (which might have been partially inferred) while the {} inferred it to '{}'", InferenceType::partial_display_name(&ctx.heap, poly_section), expr_return_name, diff --git a/src/protocol/parser/pass_validation_linking.rs b/src/protocol/parser/pass_validation_linking.rs index b2b0f9fb8780c6611bef6feda98263cd1156de02..7739f7615916753bb3033aa38e6185776a0387f9 100644 --- a/src/protocol/parser/pass_validation_linking.rs +++ b/src/protocol/parser/pass_validation_linking.rs @@ -463,10 +463,11 @@ impl Visitor for PassValidationLinking { // Although we call assignment an expression to simplify the compiler's // code (mainly typechecking), we disallow nested use in expressions match self.expr_parent { + // Look at us: lying through our teeth while providing error messages. ExpressionParent::ExpressionStmt(_) => {}, _ => return Err(ParseError::new_error_str_at_span( - &ctx.module.source, assignment_expr.span, - "assignments may only appear at the statement level" + &ctx.module.source, assignment_expr.full_span, + "assignments are statements, and cannot be used in expressions" )), } @@ -478,7 +479,7 @@ impl Visitor for PassValidationLinking { self.next_expr_index += 1; self.expr_parent = ExpressionParent::Expression(upcast_id, 0); - self.must_be_assignable = Some(assignment_expr.span); + self.must_be_assignable = Some(assignment_expr.operator_span); self.visit_expr(ctx, left_expr_id)?; self.expr_parent = ExpressionParent::Expression(upcast_id, 1); self.must_be_assignable = None; @@ -500,7 +501,7 @@ impl Visitor for PassValidationLinking { if self.in_test_expr.is_invalid() { let binding_expr = &ctx.heap[id]; return Err(ParseError::new_error_str_at_span( - &ctx.module.source, binding_expr.span, + &ctx.module.source, binding_expr.full_span, "binding expressions can only be used inside the testing expression of 'if' and 'while' statements" )); } @@ -509,10 +510,10 @@ impl Visitor for PassValidationLinking { let binding_expr = &ctx.heap[id]; let previous_expr = &ctx.heap[self.in_binding_expr]; return Err(ParseError::new_error_str_at_span( - &ctx.module.source, binding_expr.span, + &ctx.module.source, binding_expr.full_span, "nested binding expressions are not allowed" ).with_info_str_at_span( - &ctx.module.source, previous_expr.span, + &ctx.module.source, previous_expr.operator_span, "the outer binding expression is found here" )); } @@ -550,10 +551,10 @@ impl Visitor for PassValidationLinking { let binding_expr = &ctx.heap[id]; let parent_expr = &ctx.heap[seeking_parent.as_expression()]; return Err(ParseError::new_error_str_at_span( - &ctx.module.source, binding_expr.span, + &ctx.module.source, binding_expr.full_span, "only the logical-and operator (&&) may be applied to binding expressions" ).with_info_str_at_span( - &ctx.module.source, parent_expr.span(), + &ctx.module.source, parent_expr.operation_span(), "this was the disallowed operation applied to the result from a binding expression" )); } @@ -583,7 +584,7 @@ impl Visitor for PassValidationLinking { _ => { let binding_expr = &ctx.heap[id]; return Err(ParseError::new_error_str_at_span( - &ctx.module.source, binding_expr.span, + &ctx.module.source, binding_expr.operator_span, "the left hand side of a binding expression may only be a variable or a literal expression" )); }, @@ -980,13 +981,13 @@ impl Visitor for PassValidationLinking { Method::Get => { if !self.def_type.is_primitive() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "a call to 'get' may only occur in primitive component definitions" )); } if self.in_sync.is_invalid() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "a call to 'get' may only occur inside synchronous blocks" )); } @@ -994,13 +995,13 @@ impl Visitor for PassValidationLinking { Method::Put => { if !self.def_type.is_primitive() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "a call to 'put' may only occur in primitive component definitions" )); } if self.in_sync.is_invalid() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "a call to 'put' may only occur inside synchronous blocks" )); } @@ -1008,13 +1009,13 @@ impl Visitor for PassValidationLinking { Method::Fires => { if !self.def_type.is_primitive() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "a call to 'fires' may only occur in primitive component definitions" )); } if self.in_sync.is_invalid() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "a call to 'fires' may only occur inside synchronous blocks" )); } @@ -1024,13 +1025,13 @@ impl Visitor for PassValidationLinking { Method::Assert => { if self.def_type.is_function() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "assert statement may only occur in components" )); } if self.in_sync.is_invalid() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "assert statements may only occur inside synchronous blocks" )); } @@ -1044,14 +1045,14 @@ impl Visitor for PassValidationLinking { if expected_wrapping_new_stmt { if !self.expr_parent.is_new() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "cannot call a component, it can only be instantiated by using 'new'" )); } } else { if self.expr_parent.is_new() { return Err(ParseError::new_error_str_at_span( - &ctx.module.source, call_expr.span, + &ctx.module.source, call_expr.func_span, "only components can be instantiated, this is a function" )); } @@ -1069,7 +1070,7 @@ impl Visitor for PassValidationLinking { if num_provided_args != num_expected_args { let argument_text = if num_expected_args == 1 { "argument" } else { "arguments" }; return Err(ParseError::new_error_at_span( - &ctx.module.source, call_expr.span, format!( + &ctx.module.source, call_expr.full_span, format!( "expected {} {}, but {} were provided", num_expected_args, argument_text, num_provided_args ) @@ -1153,7 +1154,7 @@ impl Visitor for PassValidationLinking { &ctx.module.source, var_expr.identifier.span, "illegal location for binding variable: binding variables may only be nested under a binding expression, or a struct, union or array literal" ).with_info_at_span( - &ctx.module.source, binding_expr.span, format!( + &ctx.module.source, binding_expr.operator_span, format!( "'{}' was interpreted as a binding variable because the variable is not declared and it is nested under this binding expression", var_expr.identifier.value.as_str() ) diff --git a/src/protocol/tests/parser_inference.rs b/src/protocol/tests/parser_inference.rs index ddf5a72cbd78ddad2518dc74ec651f4d17349f3a..7158a305e382d1e0bf266849422f1ffbd621f67f 100644 --- a/src/protocol/tests/parser_inference.rs +++ b/src/protocol/tests/parser_inference.rs @@ -388,8 +388,8 @@ fn test_failed_polymorph_inference() { " ).error(|e| { e .assert_num(2) - .assert_any_msg_has("type 'Uninteresting'") - .assert_any_msg_has("type 'Uninteresting'"); + .assert_msg_has(0, "type 'Uninteresting'") + .assert_msg_has(1, "type 'Uninteresting'"); }); Tester::new_single_source_expect_err( @@ -405,7 +405,7 @@ fn test_failed_polymorph_inference() { ).error(|e| { e .assert_num(3) .assert_ctx_has(0, "holder.a") - .assert_occurs_at(0, ".") + .assert_occurs_at(0, "holder.a") .assert_msg_has(0, "Conflicting type for polymorphic variable 'Shazam'") .assert_msg_has(1, "inferred it to 's8'") .assert_msg_has(2, "inferred it to 's32'"); diff --git a/src/protocol/tests/utils.rs b/src/protocol/tests/utils.rs index 479a6cc52847075f06be1c25988721c14c95ea39..753c1f10d5a66b3962e03d16b9b9eee460627c7f 100644 --- a/src/protocol/tests/utils.rs +++ b/src/protocol/tests/utils.rs @@ -569,7 +569,7 @@ impl<'a> FunctionTester<'a> { // Use the inner match index to find the expression let expr_id = seek_expr_in_stmt( &self.ctx.heap, self.def.body.upcast(), - &|expr| expr.span().begin.offset as usize == inner_match_idx + &|expr| expr.operation_span().begin.offset as usize == inner_match_idx ); assert!( expr_id.is_some(), @@ -814,26 +814,6 @@ impl<'a> ErrorTester<'a> { self } - // TODO: @tokenizer This should really be removed, as compilation should be - // deterministic, but we're currently using rather inefficient hashsets for - // the type inference, so remove once compiler architecture has changed. - pub(crate) fn assert_any_msg_has(self, msg: &str) -> Self { - let mut is_present = false; - for statement in &self.error.statements { - if statement.message.contains(msg) { - is_present = true; - break; - } - } - - assert!( - is_present, "[{}] Expected an error statement to contain '{}' for {}", - self.test_name, msg, self.assert_postfix() - ); - - self - } - /// Seeks the index of the pattern in the context message, then checks if /// the input position corresponds to that index. pub (crate) fn assert_occurs_at(self, idx: usize, pattern: &str) -> Self {