+++ /dev/null
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package typeparams
-
-import (
- "go/ast"
- "go/token"
-)
-
-func PackIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token.Pos) ast.Expr {
- switch len(exprs) {
- case 0:
- panic("internal error: PackIndexExpr with empty expr slice")
- case 1:
- return &ast.IndexExpr{
- X: x,
- Lbrack: lbrack,
- Index: exprs[0],
- Rbrack: rbrack,
- }
- default:
- return &ast.IndexListExpr{
- X: x,
- Lbrack: lbrack,
- Indices: exprs,
- Rbrack: rbrack,
- }
- }
-}
-
-// IndexExpr wraps an ast.IndexExpr or ast.IndexListExpr.
-//
-// Orig holds the original ast.Expr from which this IndexExpr was derived.
-//
-// Note: IndexExpr (intentionally) does not wrap ast.Expr, as that leads to
-// accidental misuse such as encountered in golang/go#63933.
-//
-// TODO(rfindley): remove this helper, in favor of just having a helper
-// function that returns indices.
-type IndexExpr struct {
- Orig ast.Expr // the wrapped expr, which may be distinct from the IndexListExpr below.
- X ast.Expr // expression
- Lbrack token.Pos // position of "["
- Indices []ast.Expr // index expressions
- Rbrack token.Pos // position of "]"
-}
-
-func (x *IndexExpr) Pos() token.Pos {
- return x.Orig.Pos()
-}
-
-func UnpackIndexExpr(n ast.Node) *IndexExpr {
- switch e := n.(type) {
- case *ast.IndexExpr:
- return &IndexExpr{
- Orig: e,
- X: e.X,
- Lbrack: e.Lbrack,
- Indices: []ast.Expr{e.Index},
- Rbrack: e.Rbrack,
- }
- case *ast.IndexListExpr:
- return &IndexExpr{
- Orig: e,
- X: e.X,
- Lbrack: e.Lbrack,
- Indices: e.Indices,
- Rbrack: e.Rbrack,
- }
- }
- return nil
-}
"fmt"
"go/ast"
"go/build/constraint"
- "go/internal/typeparams"
"go/scanner"
"go/token"
"strings"
}
// x[P], x[P1, P2], ...
- return nil, typeparams.PackIndexExpr(x, lbrack, args, rbrack)
+ return nil, packIndexExpr(x, lbrack, args, rbrack)
}
func (p *parser) parseFieldDecl() *ast.Field {
p.exprLev--
}
rbrack := p.expectClosing(token.RBRACK, "type argument list")
- typ = typeparams.PackIndexExpr(ident, lbrack, list, rbrack)
+ typ = packIndexExpr(ident, lbrack, list, rbrack)
}
case p.tok == token.LPAREN:
// ordinary method
}
}
- return typeparams.PackIndexExpr(typ, opening, list, closing)
+ return packIndexExpr(typ, opening, list, closing)
}
func (p *parser) tryIdentOrType() ast.Expr {
}
// instance expression
- return typeparams.PackIndexExpr(x, lbrack, args, rbrack)
+ return packIndexExpr(x, lbrack, args, rbrack)
}
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
return f
}
+
+// packIndexExpr returns an IndexExpr x[expr0] or IndexListExpr x[expr0, ...].
+func packIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token.Pos) ast.Expr {
+ switch len(exprs) {
+ case 0:
+ panic("internal error: packIndexExpr with empty expr slice")
+ case 1:
+ return &ast.IndexExpr{
+ X: x,
+ Lbrack: lbrack,
+ Index: exprs[0],
+ Rbrack: rbrack,
+ }
+ default:
+ return &ast.IndexListExpr{
+ X: x,
+ Lbrack: lbrack,
+ Indices: exprs,
+ Rbrack: rbrack,
+ }
+ }
+}
import (
"go/ast"
- "go/internal/typeparams"
"go/token"
. "internal/types/errors"
"strings"
//
// If an error (other than a version error) occurs in any case, it is reported
// and x.mode is set to invalid.
-func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typeparams.IndexExpr, infer bool) ([]Type, []ast.Expr) {
+func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *indexedExpr, infer bool) ([]Type, []ast.Expr) {
assert(T != nil || ix != nil)
var instErrPos positioner
if ix != nil {
- instErrPos = inNode(ix.Orig, ix.Lbrack)
- x.expr = ix.Orig // if we don't have an index expression, keep the existing expression of x
+ instErrPos = inNode(ix.orig, ix.lbrack)
+ x.expr = ix.orig // if we don't have an index expression, keep the existing expression of x
} else {
instErrPos = atPos(pos)
}
var targs []Type
var xlist []ast.Expr
if ix != nil {
- xlist = ix.Indices
+ xlist = ix.indices
targs = check.typeList(xlist)
if targs == nil {
x.mode = invalid
got, want := len(targs), sig.TypeParams().Len()
if got > want {
// Providing too many type arguments is always an error.
- check.errorf(ix.Indices[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want)
+ check.errorf(ix.indices[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want)
x.mode = invalid
return nil, nil
}
}
func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
- ix := typeparams.UnpackIndexExpr(call.Fun)
+ ix := unpackIndexedExpr(call.Fun)
if ix != nil {
if check.indexExpr(x, ix) {
// Delay function instantiation to argument checking,
var xlist []ast.Expr
var targs []Type
if ix != nil {
- xlist = ix.Indices
+ xlist = ix.indices
targs = check.typeList(xlist)
if targs == nil {
check.use(call.Args...)
// is an error checking its arguments (for example, if an incorrect number
// of arguments is supplied).
if got == want && want > 0 {
- check.verifyVersionf(atPos(ix.Lbrack), go1_18, "function instantiation")
- sig = check.instantiateSignature(ix.Pos(), ix.Orig, sig, targs, xlist)
+ check.verifyVersionf(atPos(ix.lbrack), go1_18, "function instantiation")
+ sig = check.instantiateSignature(ix.Pos(), ix.orig, sig, targs, xlist)
// targs have been consumed; proceed with checking arguments of the
// non-generic signature.
targs = nil
// single value (possibly a partially instantiated function), or a multi-valued expression
e := elist[0]
var x operand
- if ix := typeparams.UnpackIndexExpr(e); ix != nil && check.indexExpr(&x, ix) {
+ if ix := unpackIndexedExpr(e); ix != nil && check.indexExpr(&x, ix) {
// x is a generic function.
targs, xlist := check.funcInst(nil, x.Pos(), &x, ix, infer)
if targs != nil {
targsList = [][]Type{targs}
xlistList = [][]ast.Expr{xlist}
// Update x.expr so that we can record the partially instantiated function.
- x.expr = ix.Orig
+ x.expr = ix.orig
} else {
// x was instantiated: we must record it here because we didn't
// use the usual expression evaluators.
xlistList = make([][]ast.Expr, n)
for i, e := range elist {
var x operand
- if ix := typeparams.UnpackIndexExpr(e); ix != nil && check.indexExpr(&x, ix) {
+ if ix := unpackIndexedExpr(e); ix != nil && check.indexExpr(&x, ix) {
// x is a generic function.
targs, xlist := check.funcInst(nil, x.Pos(), &x, ix, infer)
if targs != nil {
targsList[i] = targs
xlistList[i] = xlist
// Update x.expr so that we can record the partially instantiated function.
- x.expr = ix.Orig
+ x.expr = ix.orig
} else {
// x was instantiated: we must record it here because we didn't
// use the usual expression evaluators.
if !check.allowVersion(go1_18) {
switch call.Fun.(type) {
case *ast.IndexExpr, *ast.IndexListExpr:
- ix := typeparams.UnpackIndexExpr(call.Fun)
- check.versionErrorf(inNode(call.Fun, ix.Lbrack), go1_18, "function instantiation")
+ ix := unpackIndexedExpr(call.Fun)
+ check.versionErrorf(inNode(call.Fun, ix.lbrack), go1_18, "function instantiation")
default:
check.versionErrorf(inNode(call, call.Lparen), go1_18, "implicit function instantiation")
}
"fmt"
"go/ast"
"go/constant"
- "go/internal/typeparams"
"go/token"
. "internal/types/errors"
)
check.selector(x, e, nil, false)
case *ast.IndexExpr, *ast.IndexListExpr:
- ix := typeparams.UnpackIndexExpr(e)
+ ix := unpackIndexedExpr(e)
if check.indexExpr(x, ix) {
if !enableReverseTypeInference {
T = nil
"bytes"
"fmt"
"go/ast"
- "go/internal/typeparams"
)
// ExprString returns the (possibly shortened) string representation for x.
buf.WriteString(x.Sel.Name)
case *ast.IndexExpr, *ast.IndexListExpr:
- ix := typeparams.UnpackIndexExpr(x)
- WriteExpr(buf, ix.X)
+ ix := unpackIndexedExpr(x)
+ WriteExpr(buf, ix.x)
buf.WriteByte('[')
- writeExprList(buf, ix.Indices)
+ writeExprList(buf, ix.indices)
buf.WriteByte(']')
case *ast.SliceExpr:
import (
"go/ast"
"go/constant"
- "go/internal/typeparams"
+ "go/token"
. "internal/types/errors"
)
// If e is a valid function instantiation, indexExpr returns true.
// In that case x represents the uninstantiated function value and
// it is the caller's responsibility to instantiate the function.
-func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst bool) {
- check.exprOrType(x, e.X, true)
+func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) {
+ check.exprOrType(x, e.x, true)
// x may be generic
switch x.mode {
case invalid:
- check.use(e.Indices...)
+ check.use(e.indices...)
return false
case typexpr:
// type instantiation
x.mode = invalid
// TODO(gri) here we re-evaluate e.X - try to avoid this
- x.typ = check.varType(e.Orig)
+ x.typ = check.varType(e.orig)
if isValid(x.typ) {
x.mode = typexpr
}
// ok to continue even if indexing failed - map element type is known
x.mode = mapindex
x.typ = typ.elem
- x.expr = e.Orig
+ x.expr = e.orig
return false
case *Interface:
// ok to continue even if indexing failed - map element type is known
x.mode = mapindex
x.typ = elem
- x.expr = e.Orig
+ x.expr = e.orig
return false
}
if !valid {
// types2 uses the position of '[' for the error
check.errorf(x, NonIndexableOperand, invalidOp+"cannot index %s", x)
- check.use(e.Indices...)
+ check.use(e.indices...)
x.mode = invalid
return false
}
// singleIndex returns the (single) index from the index expression e.
// If the index is missing, or if there are multiple indices, an error
// is reported and the result is nil.
-func (check *Checker) singleIndex(expr *typeparams.IndexExpr) ast.Expr {
- if len(expr.Indices) == 0 {
- check.errorf(expr.Orig, InvalidSyntaxTree, "index expression %v with 0 indices", expr)
+func (check *Checker) singleIndex(expr *indexedExpr) ast.Expr {
+ if len(expr.indices) == 0 {
+ check.errorf(expr.orig, InvalidSyntaxTree, "index expression %v with 0 indices", expr)
return nil
}
- if len(expr.Indices) > 1 {
+ if len(expr.indices) > 1 {
// TODO(rFindley) should this get a distinct error code?
- check.error(expr.Indices[1], InvalidIndex, invalidOp+"more than one index")
+ check.error(expr.indices[1], InvalidIndex, invalidOp+"more than one index")
}
- return expr.Indices[0]
+ return expr.indices[0]
}
// index checks an index expression for validity.
return true
}
+
+// indexedExpr wraps an ast.IndexExpr or ast.IndexListExpr.
+//
+// Orig holds the original ast.Expr from which this indexedExpr was derived.
+//
+// Note: indexedExpr (intentionally) does not wrap ast.Expr, as that leads to
+// accidental misuse such as encountered in golang/go#63933.
+//
+// TODO(rfindley): remove this helper, in favor of just having a helper
+// function that returns indices.
+type indexedExpr struct {
+ orig ast.Expr // the wrapped expr, which may be distinct from the IndexListExpr below.
+ x ast.Expr // expression
+ lbrack token.Pos // position of "["
+ indices []ast.Expr // index expressions
+ rbrack token.Pos // position of "]"
+}
+
+func (x *indexedExpr) Pos() token.Pos {
+ return x.orig.Pos()
+}
+
+func unpackIndexedExpr(n ast.Node) *indexedExpr {
+ switch e := n.(type) {
+ case *ast.IndexExpr:
+ return &indexedExpr{
+ orig: e,
+ x: e.X,
+ lbrack: e.Lbrack,
+ indices: []ast.Expr{e.Index},
+ rbrack: e.Rbrack,
+ }
+ case *ast.IndexListExpr:
+ return &indexedExpr{
+ orig: e,
+ x: e.X,
+ lbrack: e.Lbrack,
+ indices: e.Indices,
+ rbrack: e.Rbrack,
+ }
+ }
+ return nil
+}
"fmt"
"go/ast"
"go/constant"
- "go/internal/typeparams"
"go/token"
. "internal/types/errors"
"slices"
// unpack type parameters, if any
switch base.(type) {
case *ast.IndexExpr, *ast.IndexListExpr:
- ix := typeparams.UnpackIndexExpr(base)
- base = ix.X
+ ix := unpackIndexedExpr(base)
+ base = ix.x
if unpackParams {
- for _, arg := range ix.Indices {
+ for _, arg := range ix.indices {
var par *ast.Ident
switch arg := arg.(type) {
case *ast.Ident:
case *ast.BadExpr:
// ignore - error already reported by parser
case nil:
- check.error(ix.Orig, InvalidSyntaxTree, "parameterized receiver contains nil parameters")
+ check.error(ix.orig, InvalidSyntaxTree, "parameterized receiver contains nil parameters")
default:
check.errorf(arg, BadDecl, "receiver type parameter %s must be an identifier", arg)
}
"fmt"
"go/ast"
"go/constant"
- "go/internal/typeparams"
. "internal/types/errors"
"strings"
)
}
case *ast.IndexExpr, *ast.IndexListExpr:
- ix := typeparams.UnpackIndexExpr(e)
- check.verifyVersionf(inNode(e, ix.Lbrack), go1_18, "type instantiation")
+ ix := unpackIndexedExpr(e)
+ check.verifyVersionf(inNode(e, ix.lbrack), go1_18, "type instantiation")
return check.instantiatedType(ix, def)
case *ast.ParenExpr:
}
}
-func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName) (res Type) {
+func (check *Checker) instantiatedType(ix *indexedExpr, def *TypeName) (res Type) {
if check.conf._Trace {
- check.trace(ix.Pos(), "-- instantiating type %s with %s", ix.X, ix.Indices)
+ check.trace(ix.Pos(), "-- instantiating type %s with %s", ix.x, ix.indices)
check.indent++
defer func() {
check.indent--
}()
var cause string
- typ := check.genericType(ix.X, &cause)
+ typ := check.genericType(ix.x, &cause)
if cause != "" {
- check.errorf(ix.Orig, NotAGenericType, invalidOp+"%s (%s)", ix.Orig, cause)
+ check.errorf(ix.orig, NotAGenericType, invalidOp+"%s (%s)", ix.orig, cause)
}
if !isValid(typ) {
return typ // error already reported
gtyp := typ.(genericType)
// evaluate arguments
- targs := check.typeList(ix.Indices)
+ targs := check.typeList(ix.indices)
if targs == nil {
return Typ[Invalid]
}
// This is an instance from the source, not from recursive substitution,
// and so it must be resolved during type-checking so that we can report
// errors.
- check.recordInstance(ix.Orig, targs, inst)
+ check.recordInstance(ix.orig, targs, inst)
name := inst.(interface{ Obj() *TypeName }).Obj().name
tparams := inst.TypeParams().list()
if i, err := check.verify(ix.Pos(), inst.TypeParams().list(), targs, check.context()); err != nil {
// best position for error reporting
pos := ix.Pos()
- if i < len(ix.Indices) {
- pos = ix.Indices[i].Pos()
+ if i < len(ix.indices) {
+ pos = ix.indices[i].Pos()
}
check.softErrorf(atPos(pos), InvalidTypeArg, "%v", err)
} else {
- check.mono.recordInstance(check.pkg, ix.Pos(), tparams, targs, ix.Indices)
+ check.mono.recordInstance(check.pkg, ix.Pos(), tparams, targs, ix.indices)
}
}
}).describef(ix, "verify instantiation %s", inst)