Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new precedence from #4075 #4236

Merged
merged 7 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions toolchain/parse/precedence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,21 @@ struct OperatorPriorityTable {
MarkHigherThan({Highest}, {TermPrefix, LogicalPrefix});
MarkHigherThan({TermPrefix},
{NumericPrefix, BitwisePrefix, IncrementDecrement});
MarkHigherThan({NumericPrefix, BitwisePrefix},
MarkHigherThan({NumericPrefix, BitwisePrefix, TypePostfix},
{As, Multiplicative, Modulo, BitwiseAnd, BitwiseOr,
BitwiseXor, BitShift});
MarkHigherThan({Multiplicative}, {Additive});
MarkHigherThan(
{As, Additive, Modulo, BitwiseAnd, BitwiseOr, BitwiseXor, BitShift},
{Additive, Modulo, BitwiseAnd, BitwiseOr, BitwiseXor, BitShift},
{Relational});
MarkHigherThan({Relational, LogicalPrefix}, {LogicalAnd, LogicalOr});
MarkHigherThan({LogicalAnd, LogicalOr}, {If});
MarkHigherThan({As, LogicalAnd, LogicalOr}, {If});
geoffromer marked this conversation as resolved.
Show resolved Hide resolved
MarkHigherThan({If}, {Assignment});
MarkHigherThan({Assignment, IncrementDecrement}, {Lowest});

// Types are mostly a separate precedence graph.
MarkHigherThan({Highest}, {TypePrefix});
MarkHigherThan({TypePrefix}, {TypePostfix});
MarkHigherThan({TypePostfix}, {As});

// Compute the transitive closure of the above relationships: if we parse
// `a $ b @ c` as `(a $ b) @ c` and parse `b @ c % d` as `(b @ c) % d`,
Expand Down
7 changes: 1 addition & 6 deletions toolchain/parse/precedence_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,12 @@ TEST(PrecedenceTest, InfixVsPostfix) {
EXPECT_FALSE(
PrecedenceGroup::ForTrailing(Lex::TokenKind::Star, false)->is_binary);

// Infix `*` can appear in `+` contexts; postfix `*` cannot.
// Infix `*` can appear in `+` contexts.
EXPECT_THAT(
PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(Lex::TokenKind::Star, true)->level,
PrecedenceGroup::ForTrailing(Lex::TokenKind::Plus, true)->level),
Eq(OperatorPriority::LeftFirst));
EXPECT_THAT(
PrecedenceGroup::GetPriority(
PrecedenceGroup::ForTrailing(Lex::TokenKind::Star, false)->level,
PrecedenceGroup::ForTrailing(Lex::TokenKind::Plus, true)->level),
Eq(OperatorPriority::Ambiguous));
}

TEST(PrecedenceTest, Associativity) {
Expand Down
56 changes: 53 additions & 3 deletions toolchain/parse/testdata/operators/fail_precedence_as.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,40 @@ fn F(n: i32) {
// CHECK:STDERR:
not true as bool;

// No ordering between most binary operators and `as`.
// No ordering between mathematical binary operators and `as`.
// CHECK:STDERR: fail_precedence_as.carbon:[[@LINE+4]]:9: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: 1 + 1 as i32;
// CHECK:STDERR: ^~
// CHECK:STDERR:
1 + 1 as i32;
// CHECK:STDERR: fail_precedence_as.carbon:[[@LINE+3]]:9: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: fail_precedence_as.carbon:[[@LINE+4]]:9: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: 5 % 2 as i32;
// CHECK:STDERR: ^~
// CHECK:STDERR:
josh11b marked this conversation as resolved.
Show resolved Hide resolved
5 % 2 as i32;

// No ordering between logical binary operators and `as`.
// CHECK:STDERR: fail_precedence_as.carbon:[[@LINE+4]]:12: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: 3 as i32 and true;
// CHECK:STDERR: ^~~
// CHECK:STDERR:
3 as i32 and true;
// CHECK:STDERR: fail_precedence_as.carbon:[[@LINE+4]]:14: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: false or 4 as i32;
// CHECK:STDERR: ^~
// CHECK:STDERR:
false or 4 as i32;

// No ordering between relational binary operators and `as`.
// CHECK:STDERR: fail_precedence_as.carbon:[[@LINE+4]]:12: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: 6 as i32 == 7;
// CHECK:STDERR: ^~
// CHECK:STDERR:
6 as i32 == 7;
// CHECK:STDERR: fail_precedence_as.carbon:[[@LINE+3]]:10: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: 8 <= 9 as i32;
// CHECK:STDERR: ^~
8 <= 9 as i32;
}

// CHECK:STDOUT: - filename: fail_precedence_as.carbon
Expand Down Expand Up @@ -56,6 +80,32 @@ fn F(n: i32) {
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 26},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '3'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ShortCircuitOperandAnd', text: 'and', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'BoolLiteralTrue', text: 'true'},
// CHECK:STDOUT: {kind: 'ShortCircuitOperatorAnd', text: 'and', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'BoolLiteralFalse', text: 'false'},
// CHECK:STDOUT: {kind: 'ShortCircuitOperandOr', text: 'or', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '4'},
// CHECK:STDOUT: {kind: 'ShortCircuitOperatorOr', text: 'or', subtree_size: 4},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '6'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '7'},
// CHECK:STDOUT: {kind: 'InfixOperatorEqualEqual', text: '==', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '8'},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '9'},
// CHECK:STDOUT: {kind: 'InfixOperatorLessEqual', text: '<=', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', has_error: yes, subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 52},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
40 changes: 13 additions & 27 deletions toolchain/parse/testdata/operators/precedence_as.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ fn F(n: i32) {
// Type operators and unary operators are higher precedence than `as`.
-n as const i32;
&n as i32*;

// `as` is higher precedence than relational comparisons and
// logical operators.
if (1 as i32 < 2 as i32 and true as bool and false as bool) {}
^n as i32;
*n as i32;
}

// CHECK:STDOUT: - filename: precedence_as.carbon
Expand All @@ -41,28 +39,16 @@ fn F(n: i32) {
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'IfConditionStart', text: '('},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '1'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '2'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 3},
// CHECK:STDOUT: {kind: 'InfixOperatorLess', text: '<', subtree_size: 7},
// CHECK:STDOUT: {kind: 'ShortCircuitOperandAnd', text: 'and', subtree_size: 8},
// CHECK:STDOUT: {kind: 'BoolLiteralTrue', text: 'true'},
// CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ShortCircuitOperatorAnd', text: 'and', subtree_size: 12},
// CHECK:STDOUT: {kind: 'ShortCircuitOperandAnd', text: 'and', subtree_size: 13},
// CHECK:STDOUT: {kind: 'BoolLiteralFalse', text: 'false'},
// CHECK:STDOUT: {kind: 'BoolTypeLiteral', text: 'bool'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ShortCircuitOperatorAnd', text: 'and', subtree_size: 17},
// CHECK:STDOUT: {kind: 'IfCondition', text: ')', subtree_size: 19},
// CHECK:STDOUT: {kind: 'CodeBlockStart', text: '{'},
// CHECK:STDOUT: {kind: 'CodeBlock', text: '}', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IfStatement', text: 'if', subtree_size: 22},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 43},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'n'},
// CHECK:STDOUT: {kind: 'PrefixOperatorCaret', text: '^', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 4},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'n'},
// CHECK:STDOUT: {kind: 'PrefixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorAs', text: 'as', subtree_size: 4},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 31},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/operators/fail_precedence_star_minus.carbon
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/operators/recover_star_minus.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/operators/fail_precedence_star_minus.carbon
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/operators/recover_star_minus.carbon

// CHECK:STDERR: fail_precedence_star_minus.carbon:[[@LINE+3]]:16: ERROR: Parentheses are required to disambiguate operator precedence.
// TODO: There are two possible fixes that would make this expression legal:
// `n * -n` and `n* - n`. The parser doesn't realize that the first fix is
// available because it has already accepted that first part of the expression,
// so it is recovering by using the second option, but the diagnostic should
// ideally offer (or consider) both fixes as alternatives.
// CHECK:STDERR: recover_star_minus.carbon:[[@LINE+3]]:16: ERROR: Whitespace missing after binary operator.
geoffromer marked this conversation as resolved.
Show resolved Hide resolved
// CHECK:STDERR: var n: i8 = n* -n;
// CHECK:STDERR: ^
var n: i8 = n* -n;

// CHECK:STDOUT: - filename: fail_precedence_star_minus.carbon
// CHECK:STDOUT: - filename: recover_star_minus.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'},
Expand All @@ -24,7 +29,7 @@ var n: i8 = n* -n;
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'n'},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'n'},
// CHECK:STDOUT: {kind: 'InfixOperatorMinus', text: '-', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'InfixOperatorMinus', text: '-', subtree_size: 4},
geoffromer marked this conversation as resolved.
Show resolved Hide resolved
// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 10},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/operators/fail_precedence_star_star.carbon
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/operators/recover_star_star.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/operators/fail_precedence_star_star.carbon
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/operators/recover_star_star.carbon

// CHECK:STDERR: fail_precedence_star_star.carbon:[[@LINE+3]]:16: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: recover_star_star.carbon:[[@LINE+3]]:16: ERROR: Whitespace missing after binary operator.
// CHECK:STDERR: var n: i8 = n* *p;
// CHECK:STDERR: ^
var n: i8 = n* *p;

// CHECK:STDOUT: - filename: fail_precedence_star_star.carbon
// CHECK:STDOUT: - filename: recover_star_star.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'},
Expand All @@ -24,7 +24,7 @@ var n: i8 = n* *p;
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'n'},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'p'},
// CHECK:STDOUT: {kind: 'InfixOperatorStar', text: '*', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'InfixOperatorStar', text: '*', subtree_size: 4},
// CHECK:STDOUT: {kind: 'VariableDecl', text: ';', subtree_size: 10},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
32 changes: 32 additions & 0 deletions toolchain/parse/testdata/operators/three_stars.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/operators/three_stars.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/operators/three_stars.carbon

fn F() {
const T* * *p;
}

// CHECK:STDOUT: - filename: three_stars.carbon
// CHECK:STDOUT: parse_tree: [
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'F'},
// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('},
// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'},
// CHECK:STDOUT: {kind: 'PrefixOperatorConst', text: 'const', subtree_size: 2},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', subtree_size: 3},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'p'},
// CHECK:STDOUT: {kind: 'PrefixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InfixOperatorStar', text: '*', subtree_size: 6},
// CHECK:STDOUT: {kind: 'ExprStatement', text: ';', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 13},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
54 changes: 0 additions & 54 deletions toolchain/parse/testdata/pointer/fail_pointer_type_in_expr.carbon
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,6 @@
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/pointer/fail_pointer_type_in_expr.carbon

fn F() -> i32 {
// TODO: Indicate the locations of both operators involved in the precedence
// error, so that it's clear what ambiguity we're referring to.
// TODO: Improve error recovery so that we recover as `3 * (i32*) * 4`, not
// as `(3 * i32)* * 4`, to suppress the second error here.
// CHECK:STDERR: fail_pointer_type_in_expr.carbon:[[@LINE+8]]:17: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: return 3 * i32* * 4;
// CHECK:STDERR: ^
// CHECK:STDERR:
// CHECK:STDERR: fail_pointer_type_in_expr.carbon:[[@LINE+4]]:19: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: return 3 * i32* * 4;
// CHECK:STDERR: ^
// CHECK:STDERR:
return 3 * i32* * 4;
}

fn G() -> i32 {
// CHECK:STDERR: fail_pointer_type_in_expr.carbon:[[@LINE+4]]:15: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: return i32* + 4;
// CHECK:STDERR: ^
// CHECK:STDERR:
return i32* + 4;
}

fn H() -> i32 {
// CHECK:STDERR: fail_pointer_type_in_expr.carbon:[[@LINE+3]]:14: ERROR: Parentheses are required to disambiguate operator precedence.
// CHECK:STDERR: return *i32*;
// CHECK:STDERR: ^
Expand All @@ -50,36 +26,6 @@ fn H() -> i32 {
// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7},
// CHECK:STDOUT: {kind: 'ReturnStatementStart', text: 'return'},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '3'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'InfixOperatorStar', text: '*', subtree_size: 3},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '4'},
// CHECK:STDOUT: {kind: 'InfixOperatorStar', text: '*', has_error: yes, subtree_size: 6},
// CHECK:STDOUT: {kind: 'ReturnStatement', text: ';', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 16},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'G'},
// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('},
// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7},
// CHECK:STDOUT: {kind: 'ReturnStatementStart', text: 'return'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntLiteral', text: '4'},
// CHECK:STDOUT: {kind: 'InfixOperatorPlus', text: '+', has_error: yes, subtree_size: 4},
// CHECK:STDOUT: {kind: 'ReturnStatement', text: ';', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 14},
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierName', text: 'H'},
// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('},
// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 7},
// CHECK:STDOUT: {kind: 'ReturnStatementStart', text: 'return'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'PrefixOperatorStar', text: '*', subtree_size: 2},
// CHECK:STDOUT: {kind: 'PostfixOperatorStar', text: '*', has_error: yes, subtree_size: 3},
Expand Down
Loading
Loading