@@ -785,9 +785,9 @@ func (p *parser) parseParamDecl(name *ast.Ident, typeSetsOK bool) (f field) {
785
785
return // don't allow ...type "|" ...
786
786
787
787
default :
788
- // TODO(rfindley): this looks incorrect in the case of type parameter
789
- // lists.
790
- p .errorExpected (p .pos , ") " )
788
+ // TODO(rfindley): this is incorrect in the case of type parameter lists
789
+ // (should be "']'" in that case)
790
+ p .errorExpected (p .pos , "')' " )
791
791
p .advance (exprEnd )
792
792
}
793
793
@@ -2592,10 +2592,12 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
2592
2592
defer un (trace (p , "TypeSpec" ))
2593
2593
}
2594
2594
2595
- ident := p .parseIdent ()
2596
- spec := & ast.TypeSpec {Doc : doc , Name : ident }
2595
+ name := p .parseIdent ()
2596
+ spec := & ast.TypeSpec {Doc : doc , Name : name }
2597
2597
2598
2598
if p .tok == token .LBRACK && p .allowGenerics () {
2599
+ // spec.Name "[" ...
2600
+ // array/slice type or type parameter list
2599
2601
lbrack := p .pos
2600
2602
p .next ()
2601
2603
if p .tok == token .IDENT {
@@ -2608,14 +2610,12 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
2608
2610
// with a "[" as in: P []E. In that case, simply parsing
2609
2611
// an expression would lead to an error: P[] is invalid.
2610
2612
// But since index or slice expressions are never constant
2611
- // and thus invalid array length expressions, if we see a
2612
- // "[" following a name it must be the start of an array
2613
- // or slice constraint. Only if we don't see a "[" do we
2614
- // need to parse a full expression.
2615
-
2616
- // Index or slice expressions are never constant and thus invalid
2617
- // array length expressions. Thus, if we see a "[" following name
2618
- // we can safely assume that "[" name starts a type parameter list.
2613
+ // and thus invalid array length expressions, if the name
2614
+ // is followed by "[" it must be the start of an array or
2615
+ // slice constraint. Only if we don't see a "[" do we
2616
+ // need to parse a full expression. Notably, name <- x
2617
+ // is not a concern because name <- x is a statement and
2618
+ // not an expression.
2619
2619
var x ast.Expr = p .parseIdent ()
2620
2620
if p .tok != token .LBRACK {
2621
2621
// To parse the expression starting with name, expand
@@ -2626,58 +2626,21 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
2626
2626
x = p .parseBinaryExpr (lhs , token .LowestPrec + 1 , false )
2627
2627
p .exprLev --
2628
2628
}
2629
-
2630
- // analyze the cases
2631
- var pname * ast.Ident // pname != nil means pname is the type parameter name
2632
- var ptype ast.Expr // ptype != nil means ptype is the type parameter type; pname != nil in this case
2633
-
2634
- switch t := x .(type ) {
2635
- case * ast.Ident :
2636
- // Unless we see a "]", we are at the start of a type parameter list.
2637
- if p .tok != token .RBRACK {
2638
- // d.Name "[" name ...
2639
- pname = t
2640
- // no ptype
2641
- }
2642
- case * ast.BinaryExpr :
2643
- // If we have an expression of the form name*T, and T is a (possibly
2644
- // parenthesized) type literal or the next token is a comma, we are
2645
- // at the start of a type parameter list.
2646
- if name , _ := t .X .(* ast.Ident ); name != nil {
2647
- if t .Op == token .MUL && (isTypeLit (t .Y ) || p .tok == token .COMMA ) {
2648
- // d.Name "[" name "*" t.Y
2649
- // d.Name "[" name "*" t.Y ","
2650
- // convert t into unary *t.Y
2651
- pname = name
2652
- ptype = & ast.StarExpr {Star : t .OpPos , X : t .Y }
2653
- }
2654
- }
2655
- if pname == nil {
2656
- // A normal binary expression. Since we passed check=false, we must
2657
- // now check its operands.
2658
- p .checkBinaryExpr (t )
2659
- }
2660
- case * ast.CallExpr :
2661
- // If we have an expression of the form name(T), and T is a (possibly
2662
- // parenthesized) type literal or the next token is a comma, we are
2663
- // at the start of a type parameter list.
2664
- if name , _ := t .Fun .(* ast.Ident ); name != nil {
2665
- if len (t .Args ) == 1 && ! t .Ellipsis .IsValid () && (isTypeLit (t .Args [0 ]) || p .tok == token .COMMA ) {
2666
- // d.Name "[" name "(" t.ArgList[0] ")"
2667
- // d.Name "[" name "(" t.ArgList[0] ")" ","
2668
- pname = name
2669
- ptype = t .Args [0 ]
2670
- }
2671
- }
2672
- }
2673
-
2674
- if pname != nil {
2675
- // d.Name "[" pname ...
2676
- // d.Name "[" pname ptype ...
2677
- // d.Name "[" pname ptype "," ...
2678
- p .parseGenericType (spec , lbrack , pname , ptype )
2629
+ // Analyze expression x. If we can split x into a type parameter
2630
+ // name, possibly followed by a type parameter type, we consider
2631
+ // this the start of a type parameter list, with some caveats:
2632
+ // a single name followed by "]" tilts the decision towards an
2633
+ // array declaration; a type parameter type that could also be
2634
+ // an ordinary expression but which is followed by a comma tilts
2635
+ // the decision towards a type parameter list.
2636
+ if pname , ptype := extractName (x , p .tok == token .COMMA ); pname != nil && (ptype != nil || p .tok != token .RBRACK ) {
2637
+ // spec.Name "[" pname ...
2638
+ // spec.Name "[" pname ptype ...
2639
+ // spec.Name "[" pname ptype "," ...
2640
+ p .parseGenericType (spec , lbrack , pname , ptype ) // ptype may be nil
2679
2641
} else {
2680
- // d.Name "[" x ...
2642
+ // spec.Name "[" pname "]" ...
2643
+ // spec.Name "[" x ...
2681
2644
spec .Type = p .parseArrayType (lbrack , x )
2682
2645
}
2683
2646
} else {
@@ -2700,17 +2663,66 @@ func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token
2700
2663
return spec
2701
2664
}
2702
2665
2703
- // isTypeLit reports whether x is a (possibly parenthesized) type literal.
2704
- func isTypeLit (x ast.Expr ) bool {
2666
+ // extractName splits the expression x into (name, expr) if syntactically
2667
+ // x can be written as name expr. The split only happens if expr is a type
2668
+ // element (per the isTypeElem predicate) or if force is set.
2669
+ // If x is just a name, the result is (name, nil). If the split succeeds,
2670
+ // the result is (name, expr). Otherwise the result is (nil, x).
2671
+ // Examples:
2672
+ //
2673
+ // x force name expr
2674
+ // ------------------------------------
2675
+ // P*[]int T/F P *[]int
2676
+ // P*E T P *E
2677
+ // P*E F nil P*E
2678
+ // P([]int) T/F P []int
2679
+ // P(E) T P E
2680
+ // P(E) F nil P(E)
2681
+ // P*E|F|~G T/F P *E|F|~G
2682
+ // P*E|F|G T P *E|F|G
2683
+ // P*E|F|G F nil P*E|F|G
2684
+ func extractName (x ast.Expr , force bool ) (* ast.Ident , ast.Expr ) {
2685
+ switch x := x .(type ) {
2686
+ case * ast.Ident :
2687
+ return x , nil
2688
+ case * ast.BinaryExpr :
2689
+ switch x .Op {
2690
+ case token .MUL :
2691
+ if name , _ := x .X .(* ast.Ident ); name != nil && (force || isTypeElem (x .Y )) {
2692
+ // x = name *x.Y
2693
+ return name , & ast.StarExpr {Star : x .OpPos , X : x .Y }
2694
+ }
2695
+ case token .OR :
2696
+ if name , lhs := extractName (x .X , force || isTypeElem (x .Y )); name != nil && lhs != nil {
2697
+ // x = name lhs|x.Y
2698
+ op := * x
2699
+ op .X = lhs
2700
+ return name , & op
2701
+ }
2702
+ }
2703
+ case * ast.CallExpr :
2704
+ if name , _ := x .Fun .(* ast.Ident ); name != nil {
2705
+ if len (x .Args ) == 1 && x .Ellipsis == token .NoPos && (force || isTypeElem (x .Args [0 ])) {
2706
+ // x = name "(" x.ArgList[0] ")"
2707
+ return name , x .Args [0 ]
2708
+ }
2709
+ }
2710
+ }
2711
+ return nil , x
2712
+ }
2713
+
2714
+ // isTypeElem reports whether x is a (possibly parenthesized) type element expression.
2715
+ // The result is false if x could be a type element OR an ordinary (value) expression.
2716
+ func isTypeElem (x ast.Expr ) bool {
2705
2717
switch x := x .(type ) {
2706
2718
case * ast.ArrayType , * ast.StructType , * ast.FuncType , * ast.InterfaceType , * ast.MapType , * ast.ChanType :
2707
2719
return true
2708
- case * ast.StarExpr :
2709
- // *T may be a pointer dereferenciation.
2710
- // Only consider *T as type literal if T is a type literal.
2711
- return isTypeLit ( x . X )
2720
+ case * ast.BinaryExpr :
2721
+ return isTypeElem ( x . X ) || isTypeElem ( x . Y )
2722
+ case * ast. UnaryExpr :
2723
+ return x . Op == token . TILDE
2712
2724
case * ast.ParenExpr :
2713
- return isTypeLit (x .X )
2725
+ return isTypeElem (x .X )
2714
2726
}
2715
2727
return false
2716
2728
}
0 commit comments