Changeset - 68a065935a85
[Not reviewed]
src/protocol/ast.rs
Show inline comments
 
@@ -151,12 +151,13 @@ define_new_ast_id!(ConditionalExpressionId, ExpressionId, index(ConditionalExpre
 
define_new_ast_id!(BinaryExpressionId, ExpressionId, index(BinaryExpression, Expression::Binary, expressions), alloc(alloc_binary_expression));
 
define_new_ast_id!(UnaryExpressionId, ExpressionId, index(UnaryExpression, Expression::Unary, expressions), alloc(alloc_unary_expression));
 
define_new_ast_id!(IndexingExpressionId, ExpressionId, index(IndexingExpression, Expression::Indexing, expressions), alloc(alloc_indexing_expression));
 
define_new_ast_id!(SlicingExpressionId, ExpressionId, index(SlicingExpression, Expression::Slicing, expressions), alloc(alloc_slicing_expression));
 
define_new_ast_id!(SelectExpressionId, ExpressionId, index(SelectExpression, Expression::Select, expressions), alloc(alloc_select_expression));
 
define_new_ast_id!(LiteralExpressionId, ExpressionId, index(LiteralExpression, Expression::Literal, expressions), alloc(alloc_literal_expression));
 
define_new_ast_id!(CastExpressionId, ExpressionId, index(CastExpression, Expression::Cast, expressions), alloc(alloc_cast_expression));
 
define_new_ast_id!(CallExpressionId, ExpressionId, index(CallExpression, Expression::Call, expressions), alloc(alloc_call_expression));
 
define_new_ast_id!(VariableExpressionId, ExpressionId, index(VariableExpression, Expression::Variable, expressions), alloc(alloc_variable_expression));
 

	
 
// TODO: @cleanup - pub qualifiers can be removed once done
 
#[derive(Debug)]
 
pub struct Heap {
 
@@ -1401,12 +1402,13 @@ pub enum Expression {
 
    Binary(BinaryExpression),
 
    Unary(UnaryExpression),
 
    Indexing(IndexingExpression),
 
    Slicing(SlicingExpression),
 
    Select(SelectExpression),
 
    Literal(LiteralExpression),
 
    Cast(CastExpression),
 
    Call(CallExpression),
 
    Variable(VariableExpression),
 
}
 

	
 
impl Expression {
 
    pub fn as_assignment(&self) -> &AssignmentExpression {
 
@@ -1483,12 +1485,13 @@ impl Expression {
 
            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::Literal(expr) => expr.span,
 
            Expression::Cast(expr) => expr.span,
 
            Expression::Call(expr) => expr.span,
 
            Expression::Variable(expr) => expr.identifier.span,
 
        }
 
    }
 
    // TODO: @cleanup
 
    pub fn parent(&self) -> &ExpressionParent {
 
@@ -1499,12 +1502,13 @@ impl Expression {
 
            Expression::Binary(expr) => &expr.parent,
 
            Expression::Unary(expr) => &expr.parent,
 
            Expression::Indexing(expr) => &expr.parent,
 
            Expression::Slicing(expr) => &expr.parent,
 
            Expression::Select(expr) => &expr.parent,
 
            Expression::Literal(expr) => &expr.parent,
 
            Expression::Cast(expr) => &expr.parent,
 
            Expression::Call(expr) => &expr.parent,
 
            Expression::Variable(expr) => &expr.parent,
 
        }
 
    }
 
    // TODO: @cleanup
 
    pub fn parent_expr_id(&self) -> Option<ExpressionId> {
 
@@ -1523,12 +1527,13 @@ impl Expression {
 
            Expression::Binary(expr) => expr.parent = parent,
 
            Expression::Unary(expr) => expr.parent = parent,
 
            Expression::Indexing(expr) => expr.parent = parent,
 
            Expression::Slicing(expr) => expr.parent = parent,
 
            Expression::Select(expr) => expr.parent = parent,
 
            Expression::Literal(expr) => expr.parent = parent,
 
            Expression::Cast(expr) => expr.parent = parent,
 
            Expression::Call(expr) => expr.parent = parent,
 
            Expression::Variable(expr) => expr.parent = parent,
 
        }
 
    }
 

	
 
    pub fn get_unique_id_in_definition(&self) -> i32 {
 
@@ -1539,12 +1544,13 @@ impl Expression {
 
            Expression::Binary(expr) => expr.unique_id_in_definition,
 
            Expression::Unary(expr) => expr.unique_id_in_definition,
 
            Expression::Indexing(expr) => expr.unique_id_in_definition,
 
            Expression::Slicing(expr) => expr.unique_id_in_definition,
 
            Expression::Select(expr) => expr.unique_id_in_definition,
 
            Expression::Literal(expr) => expr.unique_id_in_definition,
 
            Expression::Cast(expr) => expr.unique_id_in_definition,
 
            Expression::Call(expr) => expr.unique_id_in_definition,
 
            Expression::Variable(expr) => expr.unique_id_in_definition,
 
        }
 
    }
 
}
 

	
 
@@ -1695,12 +1701,24 @@ pub struct SelectExpression {
 
    pub field_name: Identifier,
 
    // Validator/Linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct CastExpression {
 
    pub this: CastExpressionId,
 
    // Parsing
 
    pub span: InputSpan, // of the "cast" keyword,
 
    pub to_type: ParserType,
 
    pub subject: ExpressionId,
 
    // Validator/linker
 
    pub parent: ExpressionParent,
 
    pub unique_id_in_definition: i32,
 
}
 

	
 
#[derive(Debug, Clone)]
 
pub struct CallExpression {
 
    pub this: CallExpressionId,
 
    // Parsing
 
    pub span: InputSpan,
 
    pub parser_type: ParserType, // of the function call, not the return type
src/protocol/ast_printer.rs
Show inline comments
 
@@ -701,12 +701,15 @@ impl ASTWriter {
 
                    }
 
                }
 

	
 
                self.kv(indent2).with_s_key("Parent")
 
                    .with_custom_val(|v| write_expression_parent(v, &expr.parent));
 
            },
 
            Expression::Cast(expr) => {
 
                todo!("print casting expression")
 
            }
 
            Expression::Call(expr) => {
 
                self.kv(indent).with_id(PREFIX_CALL_EXPR_ID, expr.this.0.index)
 
                    .with_s_key("CallExpr");
 

	
 
                let definition = &heap[expr.definition];
 
                match definition {
src/protocol/eval/executor.rs
Show inline comments
 
@@ -149,12 +149,15 @@ impl Frame {
 
                            self.expr_stack.push_back(ExprInstruction::PushValToFront);
 
                            self.serialize_expression(heap, *value_expr_id);
 
                        }
 
                    }
 
                }
 
            },
 
            Expression::Cast(_) => {
 
                todo!("casting expression");
 
            }
 
            Expression::Call(expr) => {
 
                for arg_expr_id in &expr.arguments {
 
                    self.expr_stack.push_back(ExprInstruction::PushValToFront);
 
                    self.serialize_expression(heap, *arg_expr_id);
 
                }
 
            },
 
@@ -485,12 +488,15 @@ impl Prompt {
 
                                    Value::Array(heap_pos)
 
                                }
 
                            };
 

	
 
                            cur_frame.expr_values.push_back(value);
 
                        },
 
                        Expression::Cast(_) => {
 
                            todo!("casting expression evaluation");
 
                        }
 
                        Expression::Call(expr) => {
 
                            // Push a new frame. Note that all expressions have
 
                            // been pushed to the front, so they're in the order
 
                            // of the definition.
 
                            let num_args = expr.arguments.len();
 

	
src/protocol/parser/depth_visitor.rs
Show inline comments
 
@@ -163,12 +163,16 @@ pub(crate) trait Visitor: Sized {
 
    ) -> VisitorResult {
 
        recursive_slicing_expression(self, h, expr)
 
    }
 
    fn visit_select_expression(&mut self, h: &mut Heap, expr: SelectExpressionId) -> VisitorResult {
 
        recursive_select_expression(self, h, expr)
 
    }
 
    fn visit_cast_expression(&mut self, h: &mut Heap, expr: CastExpressionId) -> VisitorResult {
 
        let subject = h[expr].subject;
 
        self.visit_expression(h, subject)
 
    }
 
    fn visit_call_expression(&mut self, h: &mut Heap, expr: CallExpressionId) -> VisitorResult {
 
        recursive_call_expression(self, h, expr)
 
    }
 
    fn visit_constant_expression(
 
        &mut self,
 
        _h: &mut Heap,
 
@@ -397,12 +401,13 @@ fn recursive_expression<T: Visitor>(
 
        Expression::Binary(expr) => this.visit_binary_expression(h, expr.this),
 
        Expression::Unary(expr) => this.visit_unary_expression(h, expr.this),
 
        Expression::Indexing(expr) => this.visit_indexing_expression(h, expr.this),
 
        Expression::Slicing(expr) => this.visit_slicing_expression(h, expr.this),
 
        Expression::Select(expr) => this.visit_select_expression(h, expr.this),
 
        Expression::Literal(expr) => this.visit_constant_expression(h, expr.this),
 
        Expression::Cast(expr) => this.visit_cast_expression(h, expr.this),
 
        Expression::Call(expr) => this.visit_call_expression(h, expr.this),
 
        Expression::Variable(expr) => this.visit_variable_expression(h, expr.this),
 
    }
 
}
 

	
 
fn recursive_assignment_expression<T: Visitor>(
src/protocol/parser/pass_definitions.rs
Show inline comments
 
@@ -701,13 +701,13 @@ impl PassDefinitions {
 
            // such that our final '>' will be consumed as well.
 
            iter.consume();
 
            let definition_id = self.cur_definition;
 
            let poly_vars = ctx.heap[definition_id].poly_vars();
 
            consume_parser_type(
 
                &module.source, iter, &ctx.symbols, &ctx.heap,
 
                &poly_vars, SymbolScope::Module(module.root_id), definition_id,
 
                poly_vars, SymbolScope::Module(module.root_id), definition_id,
 
                true, 1
 
            )?
 
        } else {
 
            // Assume inferred
 
            ParserType{ elements: vec![ParserTypeElement{
 
                full_span: channel_span, // TODO: @Span fix
 
@@ -1455,12 +1455,44 @@ impl PassDefinitions {
 
                        this,
 
                        span: ident_span,
 
                        value,
 
                        parent: ExpressionParent::None,
 
                        unique_id_in_definition: -1,
 
                    }).upcast()
 
                } else if ident_text == KW_CAST {
 
                    // Casting expression
 
                    iter.consume();
 
                    let to_type = if Some(TokenKind::OpenAngle) == iter.next() {
 
                        iter.consume();
 
                        let definition_id = self.cur_definition;
 
                        let poly_vars = ctx.heap[definition_id].poly_vars();
 
                        consume_parser_type(
 
                            &module.source, iter, &ctx.symbols, &ctx.heap,
 
                            poly_vars, SymbolScope::Module(module.root_id), definition_id,
 
                            true, 1
 
                        )?
 
                    } else {
 
                        // Automatic casting with inferred target type
 
                        ParserType{ elements: vec![ParserTypeElement{
 
                            full_span: ident_span, // TODO: @Span fix
 
                            variant: ParserTypeVariant::Inferred,
 
                        }]}
 
                    };
 

	
 
                    consume_token(&module.source, iter, TokenKind::OpenParen)?;
 
                    let subject = self.consume_expression(module, iter, ctx)?;
 
                    consume_token(&module.source, iter, TokenKind::CloseParen)?;
 

	
 
                    ctx.heap.alloc_cast_expression(|this| CastExpression{
 
                        this,
 
                        span: ident_span,
 
                        to_type,
 
                        subject,
 
                        parent: ExpressionParent::None,
 
                        unique_id_in_definition: -1,
 
                    }).upcast()
 
                } else {
 
                    // Not a builtin literal, but also not a known type. So we
 
                    // assume it is a variable expression. Although if we do,
 
                    // then if a programmer mistyped a struct/function name the
 
                    // error messages will be rather cryptic. For polymorphic
 
                    // arguments we can't really do anything at all (because it
src/protocol/parser/pass_typing.rs
Show inline comments
 
@@ -1314,25 +1314,37 @@ impl Visitor2 for PassTyping {
 
            }
 
        }
 

	
 
        self.progress_literal_expr(ctx, id)
 
    }
 

	
 
    fn visit_cast_expr(&mut self, ctx: &mut Ctx, id: CastExpressionId) -> VisitorResult {
 
        let upcast_id = id.upcast();
 
        self.insert_initial_expr_inference_type(ctx, upcast_id)?;
 

	
 
        let cast_expr = &ctx.heap[id];
 
        let subject_expr_id = cast_expr.subject;
 

	
 
        self.visit_expr(ctx, subject_expr_id)?;
 

	
 
        self.progress_cast_expr(ctx, id)
 
    }
 

	
 
    fn visit_call_expr(&mut self, ctx: &mut Ctx, id: CallExpressionId) -> VisitorResult {
 
        let upcast_id = id.upcast();
 
        self.insert_initial_expr_inference_type(ctx, upcast_id)?;
 
        self.insert_initial_call_polymorph_data(ctx, id);
 

	
 
        // By default we set the polymorph idx for calls to 0. If the call ends
 
        // up not being a polymorphic one, then we will select the default
 
        // expression types in the type table
 
        let call_expr = &ctx.heap[id];
 
        self.expr_types[call_expr.unique_id_in_definition as usize].field_or_monomorph_idx = 0;
 

	
 
        // Visit all arguments
 
        for arg_expr_id in call_expr.arguments.clone() {
 
        for arg_expr_id in call_expr.arguments.clone() { // TODO: @Performance
 
            self.visit_expr(ctx, arg_expr_id)?;
 
        }
 

	
 
        self.progress_call_expr(ctx, id)
 
    }
 

	
 
@@ -1537,12 +1549,16 @@ impl PassTyping {
 
                self.progress_select_expr(ctx, id)
 
            },
 
            Expression::Literal(expr) => {
 
                let id = expr.this;
 
                self.progress_literal_expr(ctx, id)
 
            },
 
            Expression::Cast(expr) => {
 
                let id = expr.this;
 
                self.progress_cast_expr(ctx, id)
 
            },
 
            Expression::Call(expr) => {
 
                let id = expr.this;
 
                self.progress_call_expr(ctx, id)
 
            },
 
            Expression::Variable(expr) => {
 
                let id = expr.this;
 
@@ -2286,12 +2302,23 @@ impl PassTyping {
 
        // TODO: FIX!!!!
 
        if progress_expr { self.queue_expr_parent(ctx, upcast_id); }
 

	
 
        Ok(())
 
    }
 

	
 
    fn progress_cast_expr(&mut self, ctx: &mut Ctx, id: CastExpressionId) -> Result<(), ParseError> {
 
        let upcast_id = id.upcast();
 
        let expr = &ctx.heap[id];
 
        let expr_idx = expr.unique_id_in_definition;
 

	
 
        // The cast expression acts like a blocker for two-way inference. The
 
        // only thing we can do is wait until both the input and the output
 
        // TODO: Continue here
 
        Ok(())
 
    }
 

	
 
    // TODO: @cleanup, see how this can be cleaned up once I implement
 
    //  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<(), ParseError> {
 
        let upcast_id = id.upcast();
 
        let expr = &ctx.heap[id];
src/protocol/parser/pass_validation_linking.rs
Show inline comments
 
@@ -724,12 +724,36 @@ impl Visitor2 for PassValidationLinking {
 

	
 
        self.expr_parent = old_expr_parent;
 

	
 
        Ok(())
 
    }
 

	
 
    fn visit_cast_expr(&mut self, ctx: &mut Ctx, id: CastExpressionId) -> VisitorResult {
 
        let cast_expr = &mut ctx.heap[id];
 

	
 
        if let Some(span) = self.must_be_assignable {
 
            return Err(ParseError::new_error_str_at_span(
 
                &ctx.module.source, span, "cannot assign to the result from a cast expression"
 
            ))
 
        }
 

	
 
        let upcast_id = id.upcast();
 
        let old_expr_parent = self.expr_parent;
 
        cast_expr.parent = old_expr_parent;
 
        cast_expr.unique_id_in_definition = self.next_expr_index;
 
        self.next_expr_index += 1;
 

	
 
        // Recurse into the thing that we're casting
 
        self.expr_parent = ExpressionParent::Expression(upcast_id, 0);
 
        let subject_id = cast_expr.subject;
 
        self.visit_expr(ctx, subject_id)?;
 
        self.expr_parent = old_expr_parent;
 

	
 
        Ok(())
 
    }
 

	
 
    fn visit_call_expr(&mut self, ctx: &mut Ctx, id: CallExpressionId) -> VisitorResult {
 
        let call_expr = &mut ctx.heap[id];
 

	
 
        if let Some(span) = self.must_be_assignable {
 
            return Err(ParseError::new_error_str_at_span(
 
                &ctx.module.source, span, "cannot assign to the result from a call expression"
src/protocol/parser/token_parsing.rs
Show inline comments
 
@@ -23,13 +23,14 @@ pub(crate) const KW_IMPORT:    &'static [u8] = b"import";
 

	
 
// Keywords - literals
 
pub(crate) const KW_LIT_TRUE:  &'static [u8] = b"true";
 
pub(crate) const KW_LIT_FALSE: &'static [u8] = b"false";
 
pub(crate) const KW_LIT_NULL:  &'static [u8] = b"null";
 

	
 
// Keywords - functions
 
// Keywords - function(like)s
 
pub(crate) const KW_CAST:        &'static [u8] = b"cast";
 
pub(crate) const KW_FUNC_GET:    &'static [u8] = b"get";
 
pub(crate) const KW_FUNC_PUT:    &'static [u8] = b"put";
 
pub(crate) const KW_FUNC_FIRES:  &'static [u8] = b"fires";
 
pub(crate) const KW_FUNC_CREATE: &'static [u8] = b"create";
 
pub(crate) const KW_FUNC_LENGTH: &'static [u8] = b"length";
 
pub(crate) const KW_FUNC_ASSERT: &'static [u8] = b"assert";
 
@@ -518,13 +519,13 @@ fn is_reserved_statement_keyword(text: &[u8]) -> bool {
 
        _ => false,
 
    }
 
}
 

	
 
fn is_reserved_expression_keyword(text: &[u8]) -> bool {
 
    match text {
 
        KW_LET |
 
        KW_LET | KW_CAST |
 
        KW_LIT_TRUE | KW_LIT_FALSE | KW_LIT_NULL |
 
        KW_FUNC_GET | KW_FUNC_PUT | KW_FUNC_FIRES | KW_FUNC_CREATE | KW_FUNC_ASSERT | KW_FUNC_LENGTH => true,
 
        _ => false,
 
    }
 
}
 

	
src/protocol/parser/visitor.rs
Show inline comments
 
@@ -202,12 +202,16 @@ pub(crate) trait Visitor2 {
 
                self.visit_select_expr(ctx, this)
 
            }
 
            Expression::Literal(expr) => {
 
                let this = expr.this;
 
                self.visit_literal_expr(ctx, this)
 
            }
 
            Expression::Cast(expr) => {
 
                let this = expr.this;
 
                self.visit_cast_expr(ctx, this)
 
            }
 
            Expression::Call(expr) => {
 
                let this = expr.this;
 
                self.visit_call_expr(ctx, this)
 
            }
 
            Expression::Variable(expr) => {
 
                let this = expr.this;
 
@@ -222,9 +226,10 @@ pub(crate) trait Visitor2 {
 
    fn visit_binary_expr(&mut self, _ctx: &mut Ctx, _id: BinaryExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_unary_expr(&mut self, _ctx: &mut Ctx, _id: UnaryExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_indexing_expr(&mut self, _ctx: &mut Ctx, _id: IndexingExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_slicing_expr(&mut self, _ctx: &mut Ctx, _id: SlicingExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_select_expr(&mut self, _ctx: &mut Ctx, _id: SelectExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_literal_expr(&mut self, _ctx: &mut Ctx, _id: LiteralExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_cast_expr(&mut self, _ctx: &mut Ctx, _id: CastExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_call_expr(&mut self, _ctx: &mut Ctx, _id: CallExpressionId) -> VisitorResult { Ok(()) }
 
    fn visit_variable_expr(&mut self, _ctx: &mut Ctx, _id: VariableExpressionId) -> VisitorResult { Ok(()) }
 
}
 
\ No newline at end of file
src/protocol/tests/eval_silly.rs
Show inline comments
 
@@ -184,21 +184,22 @@ fn test_struct_fields() {
 
fn test_field_selection_polymorphism() {
 
    // Bit silly, but just to be sure
 
    Tester::new_single_source_expect_ok("struct field shuffles", "
 
        struct VecXYZ<T> { T x, T y, T z }
 
        struct VecYZX<T> { T y, T z, T x }
 
        struct VecZXY<T> { T z, T x, T y }
 

	
 
        func modify_x<T>(T input) -> T {
 
            input.x = 1337;
 
            return input;
 
        }
 

	
 
        func foo() -> bool {
 
            auto xyz = VecXYZ<u16>{ x: 1, y: 2, z: 3 };
 
            auto yzx = VecYZX<u32>{ y: 2, z: 3, x: 1 };
 
    auto zxy = VecZXY<u64>{ x: 1, y: 2, z: 3 };
 
            auto zxy = VecZXY<u64>{ x: 1, y: 2, z: 3 }; // different initialization order
 

	
 
            auto mod_xyz = modify_x(xyz);
 
            auto mod_yzx = modify_x(yzx);
 
            auto mod_zxy = modify_x(zxy);
 

	
 
            return
src/protocol/tests/parser_inference.rs
Show inline comments
 
@@ -327,54 +327,54 @@ fn test_failed_variable_inference() {
 
        .assert_msg_has(1, "type 'u32'");
 
    });
 
}
 

	
 
#[test]
 
fn test_failed_polymorph_inference() {
 
    // Tester::new_single_source_expect_err(
 
    //     "function call inference mismatch",
 
    //     "
 
    //     func poly<T>(T a, T b) -> s32 { return 0; }
 
    //     func call() -> s32 {
 
    //         s8 first_arg = 5;
 
    //         s64 second_arg = 2;
 
    //         return poly(first_arg, second_arg);
 
    //     }
 
    //     "
 
    // ).error(|e| { e
 
    //     .assert_num(3)
 
    //     .assert_ctx_has(0, "poly(first_arg, second_arg)")
 
    //     .assert_occurs_at(0, "poly")
 
    //     .assert_msg_has(0, "Conflicting type for polymorphic variable 'T'")
 
    //     .assert_occurs_at(1, "second_arg")
 
    //     .assert_msg_has(1, "inferred it to 's64'")
 
    //     .assert_occurs_at(2, "first_arg")
 
    //     .assert_msg_has(2, "inferred it to 's8'");
 
    // });
 
    //
 
    // Tester::new_single_source_expect_err(
 
    //     "struct literal inference mismatch",
 
    //     "
 
    //     struct Pair<T>{ T first, T second }
 
    //     func call() -> s32 {
 
    //         s8 first_arg = 5;
 
    //         s64 second_arg = 2;
 
    //         auto pair = Pair{ first: first_arg, second: second_arg };
 
    //         return 3;
 
    //     }
 
    //     "
 
    // ).error(|e| { e
 
    //     .assert_num(3)
 
    //     .assert_ctx_has(0, "Pair{ first: first_arg, second: second_arg }")
 
    //     .assert_occurs_at(0, "Pair{")
 
    //     .assert_msg_has(0, "Conflicting type for polymorphic variable 'T'")
 
    //     .assert_occurs_at(1, "second_arg")
 
    //     .assert_msg_has(1, "inferred it to 's64'")
 
    //     .assert_occurs_at(2, "first_arg")
 
    //     .assert_msg_has(2, "inferred it to 's8'");
 
    // });
 
    Tester::new_single_source_expect_err(
 
        "function call inference mismatch",
 
        "
 
        func poly<T>(T a, T b) -> s32 { return 0; }
 
        func call() -> s32 {
 
            s8 first_arg = 5;
 
            s64 second_arg = 2;
 
            return poly(first_arg, second_arg);
 
        }
 
        "
 
    ).error(|e| { e
 
        .assert_num(3)
 
        .assert_ctx_has(0, "poly(first_arg, second_arg)")
 
        .assert_occurs_at(0, "poly")
 
        .assert_msg_has(0, "Conflicting type for polymorphic variable 'T'")
 
        .assert_occurs_at(1, "second_arg")
 
        .assert_msg_has(1, "inferred it to 's64'")
 
        .assert_occurs_at(2, "first_arg")
 
        .assert_msg_has(2, "inferred it to 's8'");
 
    });
 

	
 
    Tester::new_single_source_expect_err(
 
        "struct literal inference mismatch",
 
        "
 
        struct Pair<T>{ T first, T second }
 
        func call() -> s32 {
 
            s8 first_arg = 5;
 
            s64 second_arg = 2;
 
            auto pair = Pair{ first: first_arg, second: second_arg };
 
            return 3;
 
        }
 
        "
 
    ).error(|e| { e
 
        .assert_num(3)
 
        .assert_ctx_has(0, "Pair{ first: first_arg, second: second_arg }")
 
        .assert_occurs_at(0, "Pair{")
 
        .assert_msg_has(0, "Conflicting type for polymorphic variable 'T'")
 
        .assert_occurs_at(1, "second_arg")
 
        .assert_msg_has(1, "inferred it to 's64'")
 
        .assert_occurs_at(2, "first_arg")
 
        .assert_msg_has(2, "inferred it to 's8'");
 
    });
 

	
 
    // Cannot really test literal inference error, but this comes close
 
    Tester::new_single_source_expect_err(
 
        "enum literal inference mismatch",
 
        "
 
        enum Uninteresting<T>{ Variant }
src/protocol/tests/utils.rs
Show inline comments
 
@@ -1194,12 +1194,15 @@ fn seek_expr_in_expr<F: Fn(&Expression) -> bool>(heap: &Heap, start: ExpressionI
 
                        return Some(id)
 
                    }
 
                }
 
            }
 
            None
 
        },
 
        Expression::Cast(expr) => {
 
            seek_expr_in_expr(heap, expr.subject, f)
 
        }
 
        Expression::Call(expr) => {
 
            for arg in &expr.arguments {
 
                if let Some(id) = seek_expr_in_expr(heap, *arg, f) {
 
                    return Some(id)
 
                }
 
            }
0 comments (0 inline, 0 general)