Diagnose where in a binding that introduces a .Self that does not refer to the binding (#7517)

This is in addition to finding a `where` on the RHS of another `where`.
Since a generic binding introduces `.Self`, any `where` expression that
isn't part of a facet type modifying the binding itself would introduce
an ambiguous `.Self`.

Add virtual parse nodes for let, var, and form bindings, which goes
before the type. This allows us to track if `where` appears in the
binding's type. We only need to look for an invalid `where` if any
appeared in the type. We combine these three nodes together into a
single node kind, which requires us to remove the name from it as a
child. We move it up to the Pattern node again, and rename the
PatternStart nodes to PatternTypeStart as they are now located in the
middle of the Pattern nodes, just before the type.

And we only need to thaw `.Self` in generic bindings. Non-generic
bindings can only have `.Self` through a `where` expression, since the
name is not provided otherwise to non-generic bindings. And `where`
expressions thaw their `.Self` independently. So the binding only needs
to thaw a `.Self` that it introduced, which is only for generic
bindings.
This commit is contained in:
Dana Jansens
2026-07-22 16:45:00 +00:00
committed by GitHub
parent 21dc5cde04
commit d2ac9b3933
170 changed files with 1858 additions and 1314 deletions
+8 -7
View File
@@ -27,6 +27,7 @@ fn F() {
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'Foo'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'SelfTypeName', text: 'Self'},
@@ -34,9 +35,9 @@ fn F() {
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'RequirementEqualEqual', text: '==', subtree_size: 4},
// CHECK:STDOUT: {kind: 'WhereExpr', text: 'where', subtree_size: 7},
// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 9},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 11},
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 14},
// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 10},
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 12},
// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 15},
// CHECK:STDOUT: {kind: 'InterfaceIntroducer', text: 'interface'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'I'},
// CHECK:STDOUT: {kind: 'InterfaceDefinitionStart', text: '{', subtree_size: 3},
@@ -53,8 +54,8 @@ fn F() {
// CHECK:STDOUT: {kind: 'AssociatedConstantDecl', text: ';', subtree_size: 11},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: '}', subtree_size: 15},
// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'U'},
@@ -71,8 +72,8 @@ fn F() {
// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 2},
// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5},
// CHECK:STDOUT: {kind: 'LetIntroducer', text: 'let'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'U'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'U'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'W'},
+6 -5
View File
@@ -59,11 +59,11 @@ fn FailStar() {
var x: i32 = .
// CHECK:STDERR: fail_designator_eof.carbon:[[@LINE+95]]:21: error: expected identifier or `Self` after `.` [ExpectedIdentifierOrSelfAfterPeriod]
// CHECK:STDERR: fail_designator_eof.carbon:[[@LINE+96]]:21: error: expected identifier or `Self` after `.` [ExpectedIdentifierOrSelfAfterPeriod]
// CHECK:STDERR: // CHECK:STDOUT: ]
// CHECK:STDERR: ^
// CHECK:STDERR:
// CHECK:STDERR: fail_designator_eof.carbon:[[@LINE+91]]:21: error: `var` declarations must end with a `;` [ExpectedDeclSemi]
// CHECK:STDERR: fail_designator_eof.carbon:[[@LINE+92]]:21: error: `var` declarations must end with a `;` [ExpectedDeclSemi]
// CHECK:STDERR: // CHECK:STDOUT: ]
// CHECK:STDERR: ^
// CHECK:STDERR:
@@ -146,12 +146,13 @@ var x: i32 = .
// CHECK:STDOUT: {kind: 'FileStart', text: ''},
// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'x'},
// CHECK:STDOUT: {kind: 'BindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 4},
// CHECK:STDOUT: {kind: 'VarBindingPattern', text: ':', subtree_size: 4},
// CHECK:STDOUT: {kind: 'VariablePattern', text: 'var', subtree_size: 5},
// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='},
// CHECK:STDOUT: {kind: 'InvalidParse', text: '', has_error: yes},
// CHECK:STDOUT: {kind: 'DesignatorExpr', text: '.', has_error: yes, subtree_size: 2},
// CHECK:STDOUT: {kind: 'VariableDecl', text: '.', has_error: yes, subtree_size: 9},
// CHECK:STDOUT: {kind: 'VariableDecl', text: '.', has_error: yes, subtree_size: 10},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
+14 -14
View File
@@ -73,8 +73,8 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'NotDesignator'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IntTypeLiteral', text: 'i32'},
@@ -90,8 +90,8 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'DesignatorInParens'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'V'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'V'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'ParenExprStart', text: '('},
@@ -110,8 +110,8 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'DotSelf'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'W'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'W'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'K'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'SelfTypeName', text: 'Self'},
@@ -128,8 +128,8 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'DotKeyword'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'W'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'W'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'K'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'and', has_error: yes},
@@ -146,8 +146,8 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'PostfixAfterDesignator'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'X'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'X'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'L'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'M'},
@@ -165,8 +165,8 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'BinaryOpAfterDesignator'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Y'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Y'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'N'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'O'},
@@ -186,8 +186,8 @@ fn AfterAnd(generic Z: Q where .R impls S and () = .A);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'AfterAnd'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Z'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Z'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Q'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'R'},
+10 -10
View File
@@ -44,8 +44,8 @@ fn AndEarly(generic Z: L where .M and N);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'OneAnd'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'U'},
@@ -65,8 +65,8 @@ fn AndEarly(generic Z: L where .M and N);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'TwoAnd'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Y'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Y'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'J'},
@@ -96,8 +96,8 @@ fn AndEarly(generic Z: L where .M and N);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'AndPrefix'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InvalidParse', text: 'and', has_error: yes},
@@ -113,8 +113,8 @@ fn AndEarly(generic Z: L where .M and N);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'AndSuffix'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Y'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Y'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'J'},
@@ -135,8 +135,8 @@ fn AndEarly(generic Z: L where .M and N);
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'AndEarly'},
// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Z'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'Z'},
// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternTypeStart', text: ':'},
// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'L'},
// CHECK:STDOUT: {kind: 'WhereOperand', text: 'where', subtree_size: 2},
// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'M'},