]> Cypherpunks repositories - gostls13.git/commitdiff
go/parser, go/types, syntax, types2: report invalid uses of ... by parsers
authorRobert Griesemer <gri@golang.org>
Mon, 25 Nov 2024 21:08:34 +0000 (13:08 -0800)
committerGopher Robot <gobot@golang.org>
Mon, 3 Feb 2025 22:04:09 +0000 (14:04 -0800)
Check correct use of ...'s in parameter lists in parsers.
This allows the type checkers to assume correct ASTs with
respect to ... use.

Adjust some error messages: if a ... is used in a result
parameter list, the error is now more accurate.

Eliminate a now unused error code.

Change-Id: I66058e114e84805e24c59e570604b607ef5ff1fe
Reviewed-on: https://go-review.googlesource.com/c/go/+/631135
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
TryBot-Bypass: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>

13 files changed:
src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/signature.go
src/cmd/compile/internal/types2/typexpr.go
src/go/parser/parser.go
src/go/parser/short_test.go
src/go/types/expr.go
src/go/types/signature.go
src/go/types/typexpr.go
src/internal/types/errors/code_string.go
src/internal/types/errors/codes.go
src/internal/types/testdata/check/issues0.go
src/internal/types/testdata/examples/types.go

index 14a737c414988eaae89929e31eb8d4343eceba8a..82786859435b977d4430b71d317cfe7ea4d650b3 100644 (file)
@@ -650,7 +650,7 @@ func (p *parser) typeDecl(group *Group) Decl {
                                // d.Name "[" pname ...
                                // d.Name "[" pname ptype ...
                                // d.Name "[" pname ptype "," ...
-                               d.TParamList = p.paramList(pname, ptype, _Rbrack, true) // ptype may be nil
+                               d.TParamList = p.paramList(pname, ptype, _Rbrack, true, false) // ptype may be nil
                                d.Alias = p.gotAssign()
                                d.Type = p.typeOrNil()
                        } else {
@@ -800,7 +800,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
        var context string
        if p.got(_Lparen) {
                context = "method"
-               rcvr := p.paramList(nil, nil, _Rparen, false)
+               rcvr := p.paramList(nil, nil, _Rparen, false, false)
                switch len(rcvr) {
                case 0:
                        p.error("method has no receiver")
@@ -1469,12 +1469,12 @@ func (p *parser) funcType(context string) ([]*Field, *FuncType) {
                        p.syntaxError("empty type parameter list")
                        p.next()
                } else {
-                       tparamList = p.paramList(nil, nil, _Rbrack, true)
+                       tparamList = p.paramList(nil, nil, _Rbrack, true, false)
                }
        }
 
        p.want(_Lparen)
-       typ.ParamList = p.paramList(nil, nil, _Rparen, false)
+       typ.ParamList = p.paramList(nil, nil, _Rparen, false, true)
        typ.ResultList = p.funcResult()
 
        return tparamList, typ
@@ -1582,7 +1582,7 @@ func (p *parser) funcResult() []*Field {
        }
 
        if p.got(_Lparen) {
-               return p.paramList(nil, nil, _Rparen, false)
+               return p.paramList(nil, nil, _Rparen, false, false)
        }
 
        pos := p.pos()
@@ -1793,7 +1793,7 @@ func (p *parser) methodDecl() *Field {
 
                // A type argument list looks like a parameter list with only
                // types. Parse a parameter list and decide afterwards.
-               list := p.paramList(nil, nil, _Rbrack, false)
+               list := p.paramList(nil, nil, _Rbrack, false, false)
                if len(list) == 0 {
                        // The type parameter list is not [] but we got nothing
                        // due to other errors (reported by paramList). Treat
@@ -1962,10 +1962,11 @@ func (p *parser) paramDeclOrNil(name *Name, follow token) *Field {
                p.next()
                t.Elem = p.typeOrNil()
                if t.Elem == nil {
-                       t.Elem = p.badExpr()
+                       f.Type = p.badExpr()
                        p.syntaxError("... is missing type")
+               } else {
+                       f.Type = t
                }
-               f.Type = t
                return f
        }
 
@@ -1995,7 +1996,7 @@ func (p *parser) paramDeclOrNil(name *Name, follow token) *Field {
 // If name != nil, it is the first name after "(" or "[".
 // If typ != nil, name must be != nil, and (name, typ) is the first field in the list.
 // In the result list, either all fields have a name, or no field has a name.
-func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool) (list []*Field) {
+func (p *parser) paramList(name *Name, typ Expr, close token, requireNames, dddok bool) (list []*Field) {
        if trace {
                defer p.trace("paramList")()
        }
@@ -2109,6 +2110,23 @@ func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool)
                }
        }
 
+       // check use of ...
+       first := true // only report first occurrence
+       for i, f := range list {
+               if t, _ := f.Type.(*DotsType); t != nil && (!dddok || i+1 < len(list)) {
+                       if first {
+                               first = false
+                               if dddok {
+                                       p.errorAt(t.pos, "can only use ... with final parameter")
+                               } else {
+                                       p.errorAt(t.pos, "invalid use of ...")
+                               }
+                       }
+                       // use T instead of invalid ...T
+                       f.Type = t.Elem
+               }
+       }
+
        return
 }
 
index 2bf42d1c6f14943ab5fcc0462bf5eadd8608f4f8..28a5d788724a9085106a5430110ae0b8a5f088cc 100644 (file)
@@ -1016,9 +1016,8 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty
                check.ident(x, e, nil, false)
 
        case *syntax.DotsType:
-               // dots are handled explicitly where they are legal
-               // (array composite literals and parameter lists)
-               check.error(e, BadDotDotDotSyntax, "invalid use of '...'")
+               // dots are handled explicitly where they are valid
+               check.error(e, InvalidSyntaxTree, "invalid use of ...")
                goto Error
 
        case *syntax.BasicLit:
index de4f1eaa207fdcb3b8f0ef51db2b2348885f3003..622eb1383da00099473eaf47f4f5e6270baa8501 100644 (file)
@@ -344,7 +344,7 @@ func (check *Checker) collectParams(list []*syntax.Field, variadicOk bool) (name
                                if variadicOk && i == len(list)-1 {
                                        variadic = true
                                } else {
-                                       check.softErrorf(t, MisplacedDotDotDot, "can only use ... with final parameter in list")
+                                       check.error(t, InvalidSyntaxTree, "invalid use of ...")
                                        // ignore ... and continue
                                }
                        }
index e9b5ca9aa6c329068d2917da2dbf5dd96fca3ff9..0964c53fe058157f5e02fee21dc5508e43efae71 100644 (file)
@@ -321,10 +321,8 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) {
                return typ
 
        case *syntax.DotsType:
-               // dots are handled explicitly where they are legal
-               // (array composite literals and parameter lists)
-               check.error(e, InvalidDotDotDot, "invalid use of '...'")
-               check.use(e.Elem)
+               // dots are handled explicitly where they are valid
+               check.error(e, InvalidSyntaxTree, "invalid use of ...")
 
        case *syntax.StructType:
                typ := new(Struct)
index 533ee289beaa16e1ca85c333bc95985a9ff9c264..c2906c5bda8a38486bda6119074122eea40f353c 100644 (file)
@@ -872,7 +872,7 @@ func (p *parser) parseParamDecl(name *ast.Ident, typeSetsOK bool) (f field) {
        return
 }
 
-func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing token.Token) (params []*ast.Field) {
+func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing token.Token, dddok bool) (params []*ast.Field) {
        if p.trace {
                defer un(trace(p, "ParameterList"))
        }
@@ -1006,6 +1006,26 @@ func (p *parser) parseParameterList(name0 *ast.Ident, typ0 ast.Expr, closing tok
                }
        }
 
+       // check use of ...
+       first := true // only report first occurrence
+       for i, _ := range list {
+               f := &list[i]
+               if t, _ := f.typ.(*ast.Ellipsis); t != nil && (!dddok || i+1 < len(list)) {
+                       if first {
+                               first = false
+                               if dddok {
+                                       p.error(t.Ellipsis, "can only use ... with final parameter")
+                               } else {
+                                       p.error(t.Ellipsis, "invalid use of ...")
+                               }
+                       }
+                       // use T instead of invalid ...T
+                       // TODO(gri) would like to use `f.typ = t.Elt` but that causes problems
+                       //           with the resolver in cases of reuse of the same identifier
+                       f.typ = &ast.BadExpr{From: t.Pos(), To: t.End()}
+               }
+       }
+
        // Convert list to []*ast.Field.
        // If list contains types only, each type gets its own ast.Field.
        if named == 0 {
@@ -1050,7 +1070,7 @@ func (p *parser) parseTypeParameters() *ast.FieldList {
        lbrack := p.expect(token.LBRACK)
        var list []*ast.Field
        if p.tok != token.RBRACK {
-               list = p.parseParameterList(nil, nil, token.RBRACK)
+               list = p.parseParameterList(nil, nil, token.RBRACK, false)
        }
        rbrack := p.expect(token.RBRACK)
 
@@ -1062,32 +1082,22 @@ func (p *parser) parseTypeParameters() *ast.FieldList {
        return &ast.FieldList{Opening: lbrack, List: list, Closing: rbrack}
 }
 
-func (p *parser) parseParameters() *ast.FieldList {
+func (p *parser) parseParameters(result bool) *ast.FieldList {
        if p.trace {
                defer un(trace(p, "Parameters"))
        }
 
-       lparen := p.expect(token.LPAREN)
-       var list []*ast.Field
-       if p.tok != token.RPAREN {
-               list = p.parseParameterList(nil, nil, token.RPAREN)
-       }
-       rparen := p.expect(token.RPAREN)
-
-       return &ast.FieldList{Opening: lparen, List: list, Closing: rparen}
-}
-
-func (p *parser) parseResult() *ast.FieldList {
-       if p.trace {
-               defer un(trace(p, "Result"))
-       }
-
-       if p.tok == token.LPAREN {
-               return p.parseParameters()
+       if !result || p.tok == token.LPAREN {
+               lparen := p.expect(token.LPAREN)
+               var list []*ast.Field
+               if p.tok != token.RPAREN {
+                       list = p.parseParameterList(nil, nil, token.RPAREN, !result)
+               }
+               rparen := p.expect(token.RPAREN)
+               return &ast.FieldList{Opening: lparen, List: list, Closing: rparen}
        }
 
-       typ := p.tryIdentOrType()
-       if typ != nil {
+       if typ := p.tryIdentOrType(); typ != nil {
                list := make([]*ast.Field, 1)
                list[0] = &ast.Field{Type: typ}
                return &ast.FieldList{List: list}
@@ -1109,8 +1119,8 @@ func (p *parser) parseFuncType() *ast.FuncType {
                        p.error(tparams.Opening, "function type must have no type parameters")
                }
        }
-       params := p.parseParameters()
-       results := p.parseResult()
+       params := p.parseParameters(false)
+       results := p.parseParameters(true)
 
        return &ast.FuncType{Func: pos, Params: params, Results: results}
 }
@@ -1138,13 +1148,13 @@ func (p *parser) parseMethodSpec() *ast.Field {
                                //
                                // Interface methods do not have type parameters. We parse them for a
                                // better error message and improved error recovery.
-                               _ = p.parseParameterList(name0, nil, token.RBRACK)
+                               _ = p.parseParameterList(name0, nil, token.RBRACK, false)
                                _ = p.expect(token.RBRACK)
                                p.error(lbrack, "interface method must have no type parameters")
 
                                // TODO(rfindley) refactor to share code with parseFuncType.
-                               params := p.parseParameters()
-                               results := p.parseResult()
+                               params := p.parseParameters(false)
+                               results := p.parseParameters(true)
                                idents = []*ast.Ident{ident}
                                typ = &ast.FuncType{
                                        Func:    token.NoPos,
@@ -1173,8 +1183,8 @@ func (p *parser) parseMethodSpec() *ast.Field {
                case p.tok == token.LPAREN:
                        // ordinary method
                        // TODO(rfindley) refactor to share code with parseFuncType.
-                       params := p.parseParameters()
-                       results := p.parseResult()
+                       params := p.parseParameters(false)
+                       results := p.parseParameters(true)
                        idents = []*ast.Ident{ident}
                        typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
                default:
@@ -2578,7 +2588,7 @@ func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 *
                defer un(trace(p, "parseGenericType"))
        }
 
-       list := p.parseParameterList(name0, typ0, token.RBRACK)
+       list := p.parseParameterList(name0, typ0, token.RBRACK, false)
        closePos := p.expect(token.RBRACK)
        spec.TypeParams = &ast.FieldList{Opening: openPos, List: list, Closing: closePos}
        if p.tok == token.ASSIGN {
@@ -2775,7 +2785,7 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
 
        var recv *ast.FieldList
        if p.tok == token.LPAREN {
-               recv = p.parseParameters()
+               recv = p.parseParameters(false)
        }
 
        ident := p.parseIdent()
@@ -2790,8 +2800,8 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
                        tparams = nil
                }
        }
-       params := p.parseParameters()
-       results := p.parseResult()
+       params := p.parseParameters(false)
+       results := p.parseParameters(true)
 
        var body *ast.BlockStmt
        switch p.tok {
index 3a34e8c216bf96f61b5ab59413f9145fa450701c..9465fe0e478c556ee272c060d7d9da5a4245df43 100644 (file)
@@ -190,6 +190,14 @@ var invalids = []string{
        `package p; func f() { if true {} else ; /* ERROR "expected if statement or block" */ }`,
        `package p; func f() { if true {} else defer /* ERROR "expected if statement or block" */ f() }`,
 
+       // variadic parameter lists
+       `package p; func f(a, b ... /* ERROR "can only use ... with final parameter" */ int)`,
+       `package p; func f(a ... /* ERROR "can only use ... with final parameter" */ int, b int)`,
+       `package p; func f(... /* ERROR "can only use ... with final parameter" */ int, int)`,
+       `package p; func f() (... /* ERROR "invalid use of ..." */ int)`,
+       `package p; func f() (a, b ... /* ERROR "invalid use of ..." */ int)`,
+       `package p; func f[T ... /* ERROR "invalid use of ..." */ C]()() {}`,
+
        // generic code
        `package p; type _[_ any] int; var _ = T[] /* ERROR "expected operand" */ {}`,
        `package p; var _ func[ /* ERROR "must have no type parameters" */ T any](T)`,
index d4a08927015ac98859181b5d5e6794530bdb24cc..e2e8928a12391e62b11935ee8f779b2cf762adc4 100644 (file)
@@ -1006,9 +1006,8 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type)
                check.ident(x, e, nil, false)
 
        case *ast.Ellipsis:
-               // ellipses are handled explicitly where they are legal
-               // (array composite literals and parameter lists)
-               check.error(e, BadDotDotDotSyntax, "invalid use of '...'")
+               // ellipses are handled explicitly where they are valid
+               check.error(e, InvalidSyntaxTree, "invalid use of ...")
                goto Error
 
        case *ast.BasicLit:
index ff405318ee4ca8cd92ff1d68d9375f65f3111b6a..1738384febcc0007f0d454878d7921b73d367a07 100644 (file)
@@ -364,7 +364,7 @@ func (check *Checker) collectParams(list *ast.FieldList, variadicOk bool) (names
                        if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 {
                                variadic = true
                        } else {
-                               check.softErrorf(t, MisplacedDotDotDot, "can only use ... with final parameter in list")
+                               check.softErrorf(t, InvalidSyntaxTree, "invalid use of ...")
                                // ignore ... and continue
                        }
                }
index 7928ed8ef368de6363b5376faf9c633fc1808b9b..549a84b3cc700c0eed558facabd7618e21a76776 100644 (file)
@@ -322,10 +322,8 @@ func (check *Checker) typInternal(e0 ast.Expr, def *TypeName) (T Type) {
                // report error if we encountered [...]
 
        case *ast.Ellipsis:
-               // dots are handled explicitly where they are legal
-               // (array composite literals and parameter lists)
-               check.error(e, InvalidDotDotDot, "invalid use of '...'")
-               check.use(e.Elt)
+               // dots are handled explicitly where they are valid
+               check.error(e, InvalidSyntaxTree, "invalid use of ...")
 
        case *ast.StructType:
                typ := new(Struct)
index 9ae675ef849d87c25202d8fca499b8d4890e69d8..26d7b48ee78a6357a2d7388dbb2efa6b03a97b7c 100644 (file)
@@ -86,7 +86,6 @@ func _() {
        _ = x[MissingFieldOrMethod-76]
        _ = x[BadDotDotDotSyntax-77]
        _ = x[NonVariadicDotDotDot-78]
-       _ = x[MisplacedDotDotDot-79]
        _ = x[InvalidDotDotDot-81]
        _ = x[UncalledBuiltin-82]
        _ = x[InvalidAppend-83]
@@ -161,7 +160,7 @@ func _() {
 const (
        _Code_name_0 = "InvalidSyntaxTree"
        _Code_name_1 = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilUseWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKey"
-       _Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot"
+       _Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDot"
        _Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl"
        _Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString"
        _Code_name_5 = "InvalidClearTypeTooLargeInvalidMinMaxOperandTooNew"
@@ -169,7 +168,7 @@ const (
 
 var (
        _Code_index_1 = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 218, 234, 253, 261, 277, 295, 312, 330, 354, 362, 377, 393, 411}
-       _Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738, 756}
+       _Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738}
        _Code_index_3 = [...]uint16{0, 16, 31, 44, 54, 66, 77, 91, 104, 115, 125, 140, 151, 162, 175, 191, 208, 232, 249, 264, 274, 283, 296, 312, 328, 339, 354}
        _Code_index_4 = [...]uint16{0, 14, 30, 44, 61, 81, 94, 110, 124, 141, 158, 175, 190, 204, 218, 229, 241, 254, 271, 284, 295, 308, 320, 329, 336, 348, 364, 382, 400, 415, 432, 451, 465, 485, 497, 521, 544, 562, 584, 603}
        _Code_index_5 = [...]uint8{0, 12, 24, 44, 50}
@@ -182,7 +181,7 @@ func (i Code) String() string {
        case 1 <= i && i <= 28:
                i -= 1
                return _Code_name_1[_Code_index_1[i]:_Code_index_1[i+1]]
-       case 30 <= i && i <= 79:
+       case 30 <= i && i <= 78:
                i -= 30
                return _Code_name_2[_Code_index_2[i]:_Code_index_2[i+1]]
        case 81 <= i && i <= 106:
index c0e6aa6c2daf52e5ff939e65cefa76ca76fa1eae..f8c9eb920f5840cc97a3e3630dd2e3fe445046dd 100644 (file)
@@ -719,10 +719,7 @@ const (
 
        // MisplacedDotDotDot occurs when a "..." is used somewhere other than the
        // final argument in a function declaration.
-       //
-       // Example:
-       //      func f(...int, int)
-       MisplacedDotDotDot
+       _ // not used anymore (error reported by parser)
 
        _ // InvalidDotDotDotOperand was removed.
 
index 44a709d66ea8224083f57826ff27e42a7129e72e..2b59a9c9b5c88aa47415fccbc50421accbeb369f 100644 (file)
@@ -326,9 +326,9 @@ func issue28281b(a, b int, c ...int)
 func issue28281c(a, b, c ... /* ERROR "can only use ... with final parameter" */ int)
 func issue28281d(... /* ERROR "can only use ... with final parameter" */ int, int)
 func issue28281e(a, b, c  ... /* ERROR "can only use ... with final parameter" */ int, d int)
-func issue28281f(... /* ERROR "can only use ... with final parameter" */ int, ... /* ERROR "can only use ... with final parameter" */ int, int)
-func (... /* ERROR "invalid use of '...'" */ TT) f()
-func issue28281g() (... /* ERROR "can only use ... with final parameter" */ TT)
+func issue28281f(... /* ERROR "can only use ... with final parameter" */ int, ... int, int)
+func (... /* ERROR "invalid use of ..." */ TT) f()
+func issue28281g() (... /* ERROR "invalid use of ..." */ TT)
 
 // Issue #26234: Make various field/method lookup errors easier to read by matching cmd/compile's output
 func issue26234a(f *syn.Prog) {
index 67f1534be394792d3d77efef763b4a8ad58db488..d6da2c5f6f9f9fa8247964d25d46371366796b07 100644 (file)
@@ -114,7 +114,7 @@ type I1[T any] interface{
 }
 
 // There is no such thing as a variadic generic type.
-type _[T ... /* ERROR "invalid use of '...'" */ any] struct{}
+type _[T ... /* ERROR "invalid use of ..." */ any] struct{}
 
 // Generic interfaces may be embedded as one would expect.
 type I2 interface {