Forráskód Böngészése

Implement new precedence from #4075 (#4236)

Co-authored-by: Josh L <josh11b@users.noreply.github.com>
Co-authored-by: Geoff Romer <gromer@google.com>
josh11b 1 éve
szülő
commit
935715e704

+ 3 - 4
toolchain/parse/precedence.cpp

@@ -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});
     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`,

+ 1 - 6
toolchain/parse/precedence_test.cpp

@@ -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) {

+ 53 - 3
toolchain/parse/testdata/operators/fail_precedence_as.carbon

@@ -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:
   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
@@ -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:   ]

+ 13 - 27
toolchain/parse/testdata/operators/precedence_as.carbon

@@ -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
@@ -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:   ]

+ 10 - 5
toolchain/parse/testdata/operators/fail_precedence_star_minus.carbon → toolchain/parse/testdata/operators/recover_star_minus.carbon

@@ -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.
 // 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'},
@@ -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},
 // CHECK:STDOUT:     {kind: 'VariableDecl', text: ';', subtree_size: 10},
 // CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
 // CHECK:STDOUT:   ]

+ 5 - 5
toolchain/parse/testdata/operators/fail_precedence_star_star.carbon → toolchain/parse/testdata/operators/recover_star_star.carbon

@@ -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'},
@@ -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 - 0
toolchain/parse/testdata/operators/three_stars.carbon

@@ -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:   ]

+ 0 - 54
toolchain/parse/testdata/pointer/fail_pointer_type_in_expr.carbon

@@ -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:              ^
@@ -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},

+ 24 - 4
toolchain/parse/testdata/pointer/pointer_type.carbon

@@ -9,7 +9,9 @@
 // TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/pointer/pointer_type.carbon
 
 fn F(p: i32*) -> i32* {
-  return p;
+  f32* + 0;
+  1 * bool* * 2;
+  return 3 * i32* * *p;
 }
 
 var T: type = if true then i32* else f64*;
@@ -29,10 +31,28 @@ var T: type = if true then i32* else f64*;
 // CHECK:STDOUT:           {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
 // CHECK:STDOUT:         {kind: 'ReturnType', text: '->', subtree_size: 3},
 // CHECK:STDOUT:       {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 12},
+// CHECK:STDOUT:             {kind: 'FloatTypeLiteral', text: 'f32'},
+// CHECK:STDOUT:           {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
+// CHECK:STDOUT:           {kind: 'IntLiteral', text: '0'},
+// CHECK:STDOUT:         {kind: 'InfixOperatorPlus', text: '+', subtree_size: 4},
+// CHECK:STDOUT:       {kind: 'ExprStatement', text: ';', subtree_size: 5},
+// CHECK:STDOUT:             {kind: 'IntLiteral', text: '1'},
+// CHECK:STDOUT:               {kind: 'BoolTypeLiteral', text: 'bool'},
+// CHECK:STDOUT:             {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
+// CHECK:STDOUT:           {kind: 'InfixOperatorStar', text: '*', subtree_size: 4},
+// CHECK:STDOUT:           {kind: 'IntLiteral', text: '2'},
+// CHECK:STDOUT:         {kind: 'InfixOperatorStar', text: '*', subtree_size: 6},
+// CHECK:STDOUT:       {kind: 'ExprStatement', text: ';', subtree_size: 7},
 // CHECK:STDOUT:         {kind: 'ReturnStatementStart', text: 'return'},
-// CHECK:STDOUT:         {kind: 'IdentifierNameExpr', text: 'p'},
-// CHECK:STDOUT:       {kind: 'ReturnStatement', text: ';', subtree_size: 3},
-// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 16},
+// CHECK:STDOUT:             {kind: 'IntLiteral', text: '3'},
+// CHECK:STDOUT:               {kind: 'IntTypeLiteral', text: 'i32'},
+// CHECK:STDOUT:             {kind: 'PostfixOperatorStar', text: '*', subtree_size: 2},
+// CHECK:STDOUT:           {kind: 'InfixOperatorStar', text: '*', subtree_size: 4},
+// CHECK:STDOUT:             {kind: 'IdentifierNameExpr', text: 'p'},
+// CHECK:STDOUT:           {kind: 'PrefixOperatorStar', text: '*', subtree_size: 2},
+// CHECK:STDOUT:         {kind: 'InfixOperatorStar', text: '*', subtree_size: 7},
+// CHECK:STDOUT:       {kind: 'ReturnStatement', text: ';', subtree_size: 9},
+// CHECK:STDOUT:     {kind: 'FunctionDefinition', text: '}', subtree_size: 34},
 // CHECK:STDOUT:       {kind: 'VariableIntroducer', text: 'var'},
 // CHECK:STDOUT:         {kind: 'IdentifierName', text: 'T'},
 // CHECK:STDOUT:         {kind: 'TypeTypeLiteral', text: 'type'},