1
0
mirror of https://github.com/golang/go synced 2024-11-22 20:24:47 -07:00

[dev.typeparams] go/types: use a new ast.ListExpr for multi-type instances

Modify go/parser to consistently represent type instantiation as an
ast.IndexExpr, rather than use an ast.CallExpr (with Brackets:true) for
instantiations with multiple type parameters. To enable this, introduce
a new ast expr type: ListExpr.

This brings go/types in line with types2, with the exception of a small
change to funcInst to eliminate redundant errors if values are
erroneously used as types. In a subsequent CL, call.go and expr.go will
be marked as reviewed.

This also catches some type instance syntax using '()' that was
previously accepted incorrectly. Tests are updated accordingly.

Change-Id: I30cd0181c7608f1be7486a9a8b63df993b412e85
Reviewed-on: https://go-review.googlesource.com/c/go/+/293010
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Rob Findley 2021-02-16 19:56:38 -05:00 committed by Robert Findley
parent 7b679617f3
commit 5ecb9a7887
14 changed files with 233 additions and 226 deletions

View File

@ -372,9 +372,13 @@ type (
Args []Expr // function arguments; or nil Args []Expr // function arguments; or nil
Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...") Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...")
Rparen token.Pos // position of ")" Rparen token.Pos // position of ")"
// TODO(rFindley) use a new ListExpr type rather than overloading CallExpr }
// via Brackets, as is done in the syntax package
Brackets bool // if set, "[" and "]" are used instead of "(" and ")" // A ListExpr node represents a list of expressions separated by commas.
// ListExpr nodes are used as index in IndexExpr nodes representing type
// or function instantiations with more than one type argument.
ListExpr struct {
ElemList []Expr
} }
// A StarExpr node represents an expression of the form "*" Expression. // A StarExpr node represents an expression of the form "*" Expression.
@ -493,12 +497,18 @@ func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() }
func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() } func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() }
func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() } func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() }
func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() } func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() }
func (x *StarExpr) Pos() token.Pos { return x.Star } func (x *ListExpr) Pos() token.Pos {
func (x *UnaryExpr) Pos() token.Pos { return x.OpPos } if len(x.ElemList) > 0 {
func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() } return x.ElemList[0].Pos()
func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() } }
func (x *ArrayType) Pos() token.Pos { return x.Lbrack } return token.NoPos
func (x *StructType) Pos() token.Pos { return x.Struct } }
func (x *StarExpr) Pos() token.Pos { return x.Star }
func (x *UnaryExpr) Pos() token.Pos { return x.OpPos }
func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() }
func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() }
func (x *ArrayType) Pos() token.Pos { return x.Lbrack }
func (x *StructType) Pos() token.Pos { return x.Struct }
func (x *FuncType) Pos() token.Pos { func (x *FuncType) Pos() token.Pos {
if x.Func.IsValid() || x.Params == nil { // see issue 3870 if x.Func.IsValid() || x.Params == nil { // see issue 3870
return x.Func return x.Func
@ -526,12 +536,18 @@ func (x *IndexExpr) End() token.Pos { return x.Rbrack + 1 }
func (x *SliceExpr) End() token.Pos { return x.Rbrack + 1 } func (x *SliceExpr) End() token.Pos { return x.Rbrack + 1 }
func (x *TypeAssertExpr) End() token.Pos { return x.Rparen + 1 } func (x *TypeAssertExpr) End() token.Pos { return x.Rparen + 1 }
func (x *CallExpr) End() token.Pos { return x.Rparen + 1 } func (x *CallExpr) End() token.Pos { return x.Rparen + 1 }
func (x *StarExpr) End() token.Pos { return x.X.End() } func (x *ListExpr) End() token.Pos {
func (x *UnaryExpr) End() token.Pos { return x.X.End() } if len(x.ElemList) > 0 {
func (x *BinaryExpr) End() token.Pos { return x.Y.End() } return x.ElemList[len(x.ElemList)-1].End()
func (x *KeyValueExpr) End() token.Pos { return x.Value.End() } }
func (x *ArrayType) End() token.Pos { return x.Elt.End() } return token.NoPos
func (x *StructType) End() token.Pos { return x.Fields.End() } }
func (x *StarExpr) End() token.Pos { return x.X.End() }
func (x *UnaryExpr) End() token.Pos { return x.X.End() }
func (x *BinaryExpr) End() token.Pos { return x.Y.End() }
func (x *KeyValueExpr) End() token.Pos { return x.Value.End() }
func (x *ArrayType) End() token.Pos { return x.Elt.End() }
func (x *StructType) End() token.Pos { return x.Fields.End() }
func (x *FuncType) End() token.Pos { func (x *FuncType) End() token.Pos {
if x.Results != nil { if x.Results != nil {
return x.Results.End() return x.Results.End()
@ -557,6 +573,7 @@ func (*IndexExpr) exprNode() {}
func (*SliceExpr) exprNode() {} func (*SliceExpr) exprNode() {}
func (*TypeAssertExpr) exprNode() {} func (*TypeAssertExpr) exprNode() {}
func (*CallExpr) exprNode() {} func (*CallExpr) exprNode() {}
func (*ListExpr) exprNode() {}
func (*StarExpr) exprNode() {} func (*StarExpr) exprNode() {}
func (*UnaryExpr) exprNode() {} func (*UnaryExpr) exprNode() {}
func (*BinaryExpr) exprNode() {} func (*BinaryExpr) exprNode() {}

View File

@ -119,23 +119,22 @@ func main() {
// 40 . . . . . . . } // 40 . . . . . . . }
// 41 . . . . . . . Ellipsis: - // 41 . . . . . . . Ellipsis: -
// 42 . . . . . . . Rparen: 4:25 // 42 . . . . . . . Rparen: 4:25
// 43 . . . . . . . Brackets: false // 43 . . . . . . }
// 44 . . . . . . } // 44 . . . . . }
// 45 . . . . . } // 45 . . . . }
// 46 . . . . } // 46 . . . . Rbrace: 5:1
// 47 . . . . Rbrace: 5:1 // 47 . . . }
// 48 . . . } // 48 . . }
// 49 . . } // 49 . }
// 50 . } // 50 . Scope: *ast.Scope {
// 51 . Scope: *ast.Scope { // 51 . . Objects: map[string]*ast.Object (len = 1) {
// 52 . . Objects: map[string]*ast.Object (len = 1) { // 52 . . . "main": *(obj @ 11)
// 53 . . . "main": *(obj @ 11) // 53 . . }
// 54 . . } // 54 . }
// 55 . } // 55 . Unresolved: []*ast.Ident (len = 1) {
// 56 . Unresolved: []*ast.Ident (len = 1) { // 56 . . 0: *(obj @ 29)
// 57 . . 0: *(obj @ 29) // 57 . }
// 58 . } // 58 }
// 59 }
} }
// This example illustrates how to remove a variable declaration // This example illustrates how to remove a variable declaration

View File

@ -754,7 +754,7 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
} }
// x[P], x[P1, P2], ... // x[P], x[P1, P2], ...
return nil, &ast.CallExpr{Fun: x, Lparen: lbrack, Args: args, Rparen: rbrack, Brackets: true} return nil, &ast.IndexExpr{X: x, Lbrack: lbrack, Index: &ast.ListExpr{ElemList: args}, Rbrack: rbrack}
} }
func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
@ -1153,7 +1153,7 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
p.exprLev-- p.exprLev--
} }
rbrack := p.expectClosing(token.RBRACK, "type argument list") rbrack := p.expectClosing(token.RBRACK, "type argument list")
typ = &ast.CallExpr{Fun: ident, Lparen: lbrack, Args: list, Rparen: rbrack, Brackets: true} typ = &ast.IndexExpr{X: ident, Lbrack: lbrack, Index: &ast.ListExpr{ElemList: list}, Rbrack: rbrack}
} }
case p.tok == token.LPAREN: case p.tok == token.LPAREN:
// ordinary method // ordinary method
@ -1281,7 +1281,7 @@ func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr {
closing := p.expectClosing(token.RBRACK, "type argument list") closing := p.expectClosing(token.RBRACK, "type argument list")
return &ast.CallExpr{Fun: typ, Lparen: opening, Args: list, Rparen: closing, Brackets: true} return &ast.IndexExpr{X: typ, Lbrack: opening, Index: &ast.ListExpr{ElemList: list}, Rbrack: closing}
} }
// If the result is an identifier, it is not resolved. // If the result is an identifier, it is not resolved.
@ -1557,7 +1557,7 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr {
} }
// instance expression // instance expression
return &ast.CallExpr{Fun: x, Lparen: lbrack, Args: args, Rparen: rbrack, Brackets: true} return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: &ast.ListExpr{ElemList: args}, Rbrack: rbrack}
} }
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
@ -1773,17 +1773,12 @@ func (p *parser) parsePrimaryExpr(lhs bool) (x ast.Expr) {
// type; accept it but complain if we have a complit // type; accept it but complain if we have a complit
t := unparen(x) t := unparen(x)
// determine if '{' belongs to a composite literal or a block statement // determine if '{' belongs to a composite literal or a block statement
switch t := t.(type) { switch t.(type) {
case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr: case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr:
if p.exprLev < 0 { if p.exprLev < 0 {
return return
} }
// x is possibly a composite literal type // x is possibly a composite literal type
case *ast.CallExpr:
if !t.Brackets || p.exprLev < 0 {
return
}
// x is possibly a composite literal type
case *ast.IndexExpr: case *ast.IndexExpr:
if p.exprLev < 0 { if p.exprLev < 0 {
return return

View File

@ -870,7 +870,11 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
// TODO(gri): should treat[] like parentheses and undo one level of depth // TODO(gri): should treat[] like parentheses and undo one level of depth
p.expr1(x.X, token.HighestPrec, 1) p.expr1(x.X, token.HighestPrec, 1)
p.print(x.Lbrack, token.LBRACK) p.print(x.Lbrack, token.LBRACK)
p.expr0(x.Index, depth+1) if e, _ := x.Index.(*ast.ListExpr); e != nil {
p.exprList(x.Lbrack, e.ElemList, depth+1, commaTerm, x.Rbrack, false)
} else {
p.expr0(x.Index, depth+1)
}
p.print(x.Rbrack, token.RBRACK) p.print(x.Rbrack, token.RBRACK)
case *ast.SliceExpr: case *ast.SliceExpr:
@ -919,32 +923,25 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
depth++ depth++
} }
var wasIndented bool var wasIndented bool
if x.Brackets { if _, ok := x.Fun.(*ast.FuncType); ok {
// conversions to literal function types require parentheses around the type
p.print(token.LPAREN)
wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth) wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
p.print(x.Lparen, token.LBRACK) p.print(token.RPAREN)
p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
p.print(x.Rparen, token.RBRACK)
} else { } else {
if _, ok := x.Fun.(*ast.FuncType); ok { wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
// conversions to literal function types require parentheses around the type
p.print(token.LPAREN)
wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
p.print(token.RPAREN)
} else {
wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
}
p.print(x.Lparen, token.LPAREN)
if x.Ellipsis.IsValid() {
p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
p.print(x.Ellipsis, token.ELLIPSIS)
if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
p.print(token.COMMA, formfeed)
}
} else {
p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
}
p.print(x.Rparen, token.RPAREN)
} }
p.print(x.Lparen, token.LPAREN)
if x.Ellipsis.IsValid() {
p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
p.print(x.Ellipsis, token.ELLIPSIS)
if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
p.print(token.COMMA, formfeed)
}
} else {
p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
}
p.print(x.Rparen, token.RPAREN)
if wasIndented { if wasIndented {
p.print(unindent) p.print(unindent)
} }

View File

@ -325,8 +325,8 @@ func TestTypesInfo(t *testing.T) {
{broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`}, {broken + `x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
// parameterized functions // parameterized functions
{genericPkg + `p0; func f[T any](T); var _ = f(int)`, `f`, `func[T₁ interface{}](T₁)`}, {genericPkg + `p0; func f[T any](T); var _ = f[int]`, `f`, `func[T₁ interface{}](T₁)`},
{genericPkg + `p1; func f[T any](T); var _ = f(int)`, `f(int)`, `func(int)`}, {genericPkg + `p1; func f[T any](T); var _ = f[int]`, `f[int]`, `func(int)`},
{genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ interface{}](T₁)`}, {genericPkg + `p2; func f[T any](T); func _() { f(42) }`, `f`, `func[T₁ interface{}](T₁)`},
{genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`}, {genericPkg + `p3; func f[T any](T); func _() { f(42) }`, `f(42)`, `()`},

View File

@ -303,6 +303,20 @@ func (check *Checker) assignVars(lhs, origRHS []ast.Expr) {
} }
} }
// unpack unpacks an *ast.ListExpr into a list of ast.Expr.
// TODO(gri) Should find a more efficient solution that doesn't
// require introduction of a new slice for simple
// expressions.
func unpackExpr(x ast.Expr) []ast.Expr {
if x, _ := x.(*ast.ListExpr); x != nil {
return x.ElemList
}
if x != nil {
return []ast.Expr{x}
}
return nil
}
func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) { func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) {
top := len(check.delayed) top := len(check.delayed)
scope := check.scope scope := check.scope

View File

@ -14,25 +14,103 @@ import (
"unicode" "unicode"
) )
// TODO(rFindley) this has diverged a bit from types2. Bring it up to date. // funcInst type-checks a function instantiaton inst and returns the result in x.
// If call == nil, the "call" was an index expression, and orig is of type *ast.IndexExpr. // The operand x must be the evaluation of inst.X and its type must be a signature.
func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKind { func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) {
assert(orig != nil) args, ok := check.exprOrTypeList(unpackExpr(inst.Index))
if call != nil { if !ok {
assert(call == orig) x.mode = invalid
check.exprOrType(x, call.Fun) x.expr = inst
} else { return
// We must have an index expression.
// x has already been set up (evaluation of orig.X).
// Set up fake call so we can use its fields below.
expr := orig.(*ast.IndexExpr)
call = &ast.CallExpr{Fun: expr.X, Lparen: expr.Lbrack, Args: []ast.Expr{expr.Index}, Rparen: expr.Rbrack, Brackets: true}
} }
if len(args) > 0 && args[0].mode != typexpr {
check.errorf(args[0], _NotAType, "%s is not a type", args[0])
ok = false
}
// check number of type arguments
n := len(args)
sig := x.typ.(*Signature)
if n > len(sig.tparams) {
check.errorf(args[n-1], _Todo, "got %d type arguments but want %d", n, len(sig.tparams))
x.mode = invalid
x.expr = inst
return
}
// collect types
targs := make([]Type, n)
// TODO(rFindley) use a positioner here? instantiate would need to be
// updated accordingly.
poslist := make([]token.Pos, n)
for i, a := range args {
if a.mode != typexpr {
// error was reported earlier
x.mode = invalid
x.expr = inst
return
}
targs[i] = a.typ
poslist[i] = a.Pos()
}
// if we don't have enough type arguments, use constraint type inference
var inferred bool
if n < len(sig.tparams) {
var failed int
targs, failed = check.inferB(sig.tparams, targs)
if targs == nil {
// error was already reported
x.mode = invalid
x.expr = inst
return
}
if failed >= 0 {
// at least one type argument couldn't be inferred
assert(targs[failed] == nil)
tpar := sig.tparams[failed]
check.errorf(inNode(inst, inst.Rbrack), 0, "cannot infer %s (%v) (%s)", tpar.name, tpar.pos, targs)
x.mode = invalid
x.expr = inst
return
}
// all type arguments were inferred sucessfully
if debug {
for _, targ := range targs {
assert(targ != nil)
}
}
n = len(targs)
inferred = true
}
assert(n == len(sig.tparams))
// instantiate function signature
for i, typ := range targs {
// some positions may be missing if types are inferred
var pos token.Pos
if i < len(poslist) {
pos = poslist[i]
}
check.ordinaryType(atPos(pos), typ)
}
res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
assert(res.tparams == nil) // signature is not generic anymore
if inferred {
check.recordInferred(inst, targs, res)
}
x.typ = res
x.mode = value
x.expr = inst
}
func (check *Checker) call(x *operand, call *ast.CallExpr) exprKind {
check.exprOrType(x, call.Fun)
switch x.mode { switch x.mode {
case invalid: case invalid:
check.use(call.Args...) check.use(call.Args...)
x.expr = orig x.expr = call
return statement return statement
case typexpr: case typexpr:
@ -72,7 +150,7 @@ func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKi
check.use(call.Args...) check.use(call.Args...)
check.errorf(call.Args[n-1], _WrongArgCount, "too many arguments in conversion to %s", T) check.errorf(call.Args[n-1], _WrongArgCount, "too many arguments in conversion to %s", T)
} }
x.expr = orig x.expr = call
return conversion return conversion
case builtin: case builtin:
@ -80,7 +158,7 @@ func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKi
if !check.builtin(x, call, id) { if !check.builtin(x, call, id) {
x.mode = invalid x.mode = invalid
} }
x.expr = orig x.expr = call
// a non-constant result implies a function call // a non-constant result implies a function call
if x.mode != invalid && x.mode != constant_ { if x.mode != invalid && x.mode != constant_ {
check.hasCallOrRecv = true check.hasCallOrRecv = true
@ -95,109 +173,18 @@ func (check *Checker) call(x *operand, call *ast.CallExpr, orig ast.Expr) exprKi
if sig == nil { if sig == nil {
check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x) check.invalidOp(x, _InvalidCall, "cannot call non-function %s", x)
x.mode = invalid x.mode = invalid
x.expr = orig x.expr = call
return statement return statement
} }
// evaluate arguments // evaluate arguments
args, ok := check.exprOrTypeList(call.Args) args, ok := check.exprOrTypeList(call.Args)
if ok && call.Brackets && len(args) > 0 && args[0].mode != typexpr {
check.errorf(args[0], _NotAType, "%s is not a type", args[0])
ok = false
}
if !ok { if !ok {
x.mode = invalid x.mode = invalid
x.expr = orig x.expr = call
return expression return expression
} }
// instantiate function if needed
if n := len(args); n > 0 && len(sig.tparams) > 0 && args[0].mode == typexpr {
// If the first argument is a type, assume we have explicit type arguments.
// check number of type arguments
if n > len(sig.tparams) {
check.errorf(args[n-1], _Todo, "got %d type arguments but want %d", n, len(sig.tparams))
x.mode = invalid
x.expr = orig
return expression
}
// collect types
targs := make([]Type, n)
// TODO(rFindley) use a positioner here? instantiate would need to be
// updated accordingly.
poslist := make([]token.Pos, n)
for i, a := range args {
if a.mode != typexpr {
// error was reported earlier
x.mode = invalid
x.expr = orig
return expression
}
targs[i] = a.typ
poslist[i] = a.Pos()
}
// if we don't have enough type arguments, use constraint type inference
var inferred bool
if n < len(sig.tparams) {
var failed int
targs, failed = check.inferB(sig.tparams, targs)
if targs == nil {
// error was already reported
x.mode = invalid
x.expr = orig
return expression
}
if failed >= 0 {
// at least one type argument couldn't be inferred
assert(targs[failed] == nil)
tpar := sig.tparams[failed]
ppos := check.fset.Position(tpar.pos).String()
check.errorf(inNode(call, call.Rparen), 0, "cannot infer %s (%s) (%s)", tpar.name, ppos, targs)
x.mode = invalid
x.expr = orig
return expression
}
// all type arguments were inferred sucessfully
if debug {
for _, targ := range targs {
assert(targ != nil)
}
}
n = len(targs)
inferred = true
}
assert(n == len(sig.tparams))
// instantiate function signature
for i, typ := range targs {
// some positions may be missing if types are inferred
var pos token.Pos
if i < len(poslist) {
pos = poslist[i]
}
check.ordinaryType(atPos(pos), typ)
}
res := check.instantiate(x.Pos(), sig, targs, poslist).(*Signature)
assert(res.tparams == nil) // signature is not generic anymore
if inferred {
check.recordInferred(orig, targs, res)
}
x.typ = res
x.mode = value
x.expr = orig
return expression
}
// If we reach here, orig must have been a regular call, not an index
// expression.
// TODO(rFindley) with a manually constructed AST it is possible to reach
// this assertion. We should return an invalidAST error here
// rather than panicking.
assert(!call.Brackets)
sig = check.arguments(call, sig, args) sig = check.arguments(call, sig, args)
// determine result // determine result

View File

@ -50,7 +50,7 @@ func new[T any]() *T {
// result type from the assignment to keep things simple and // result type from the assignment to keep things simple and
// easy to understand. // easy to understand.
var _ = new[int]() var _ = new[int]()
var _ *float64 = new(float64)() // the result type is indeed *float64 var _ *float64 = new[float64]() // the result type is indeed *float64
// A function may have multiple type parameters, of course. // A function may have multiple type parameters, of course.
func foo[A, B, C any](a A, b []B, c *C) B { func foo[A, B, C any](a A, b []B, c *C) B {
@ -59,7 +59,7 @@ func foo[A, B, C any](a A, b []B, c *C) B {
} }
// As before, we can pass type parameters explicitly. // As before, we can pass type parameters explicitly.
var s = foo[int, string, float64](1, []string{"first"}, new(float64)()) var s = foo[int, string, float64](1, []string{"first"}, new[float64]())
// Or we can use type inference. // Or we can use type inference.
var _ float64 = foo(42, []float64{1.0}, &s) var _ float64 = foo(42, []float64{1.0}, &s)

View File

@ -1459,7 +1459,8 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
if x.mode == value { if x.mode == value {
if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 { if sig := asSignature(x.typ); sig != nil && len(sig.tparams) > 0 {
return check.call(x, nil, e) check.funcInst(x, e)
return expression
} }
} }
@ -1739,7 +1740,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
x.typ = T x.typ = T
case *ast.CallExpr: case *ast.CallExpr:
return check.call(x, e, e) return check.call(x, e)
case *ast.StarExpr: case *ast.StarExpr:
check.exprOrType(x, e.X) check.exprOrType(x, e.X)

View File

@ -72,6 +72,14 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
WriteExpr(buf, x.Index) WriteExpr(buf, x.Index)
buf.WriteByte(']') buf.WriteByte(']')
case *ast.ListExpr:
for i, e := range x.ElemList {
if i > 0 {
buf.WriteString(", ")
}
WriteExpr(buf, e)
}
case *ast.SliceExpr: case *ast.SliceExpr:
WriteExpr(buf, x.X) WriteExpr(buf, x.X)
buf.WriteByte('[') buf.WriteByte('[')
@ -98,16 +106,12 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
case *ast.CallExpr: case *ast.CallExpr:
WriteExpr(buf, x.Fun) WriteExpr(buf, x.Fun)
var l, r byte = '(', ')' buf.WriteByte('(')
if x.Brackets {
l, r = '[', ']'
}
buf.WriteByte(l)
writeExprList(buf, x.Args) writeExprList(buf, x.Args)
if x.Ellipsis.IsValid() { if x.Ellipsis.IsValid() {
buf.WriteString("...") buf.WriteString("...")
} }
buf.WriteByte(r) buf.WriteByte(')')
case *ast.StarExpr: case *ast.StarExpr:
buf.WriteByte('*') buf.WriteByte('*')

View File

@ -494,13 +494,10 @@ L: // unpack receiver type
} }
// unpack type parameters, if any // unpack type parameters, if any
switch ptyp := rtyp.(type) { if ptyp, _ := rtyp.(*ast.IndexExpr); ptyp != nil {
case *ast.IndexExpr: rtyp = ptyp.X
panic("unimplemented")
case *ast.CallExpr:
rtyp = ptyp.Fun
if unpackParams { if unpackParams {
for _, arg := range ptyp.Args { for _, arg := range unpackExpr(ptyp.Index) {
var par *ast.Ident var par *ast.Ident
switch arg := arg.(type) { switch arg := arg.(type) {
case *ast.Ident: case *ast.Ident:

View File

@ -21,7 +21,7 @@ func _() {
eql(x, x) eql(x, x)
eql(y, y) eql(y, y)
eql(y, nil) eql(y, nil)
eql(io.Reader)(nil, nil) eql[io.Reader](nil, nil)
} }
// If we have a receiver of pointer type (below: *T) we must ignore // If we have a receiver of pointer type (below: *T) we must ignore
@ -55,8 +55,8 @@ func (T) m1()
func (*T) m2() func (*T) m2()
func _() { func _() {
f2(T /* ERROR wrong method signature */ )() f2[T /* ERROR wrong method signature */]()
f2(*T)() f2[*T]()
} }
// When a type parameter is used as an argument to instantiate a parameterized // When a type parameter is used as an argument to instantiate a parameterized
@ -244,7 +244,7 @@ func append[T interface{}, S sliceOf[T], T2 interface{ type T }](s S, t ...T2) S
var f func() var f func()
var cancelSlice []context.CancelFunc var cancelSlice []context.CancelFunc
var _ = append(context.CancelFunc, []context.CancelFunc, context.CancelFunc)(cancelSlice, f) var _ = append[context.CancelFunc, []context.CancelFunc, context.CancelFunc](cancelSlice, f)
// A generic function must be instantiated with a type, not a value. // A generic function must be instantiated with a type, not a value.

View File

@ -38,7 +38,7 @@ var _ = f(0 /* ERROR cannot use 0 .* as \[\]chan int */ )
func swap[A, B any](a A, b B) (B, A) { return b, a } func swap[A, B any](a A, b B) (B, A) { return b, a }
var _ = swap /* ERROR single value is expected */ [int, float32](1, 2) var _ = swap /* ERROR single value is expected */ [int, float32](1, 2)
var f32, i = swap[int, float32](swap(float32, int)(1, 2)) var f32, i = swap[int, float32](swap[float32, int](1, 2))
var _ float32 = f32 var _ float32 = f32
var _ int = i var _ int = i
@ -76,11 +76,11 @@ var _ *int = new[int]()
func _[T any](map[T /* ERROR incomparable map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable func _[T any](map[T /* ERROR incomparable map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable
func f1[T1 any](struct{T1}) int func f1[T1 any](struct{T1}) int
var _ = f1(int)(struct{T1}{}) var _ = f1[int](struct{T1}{})
type T1 = int type T1 = int
func f2[t1 any](struct{t1; x float32}) int func f2[t1 any](struct{t1; x float32}) int
var _ = f2(t1)(struct{t1; x float32}{}) var _ = f2[t1](struct{t1; x float32}{})
type t1 = int type t1 = int
@ -216,9 +216,9 @@ var _ = f8(1) /* ERROR not enough arguments */
var _ = f8(1, 2.3) var _ = f8(1, 2.3)
var _ = f8(1, 2.3, 3.4, 4.5) var _ = f8(1, 2.3, 3.4, 4.5)
var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ ) var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ )
var _ = f8(int, float64)(1, 2.3, 3.4, 4) var _ = f8[int, float64](1, 2.3, 3.4, 4)
var _ = f8(int, float64)(0, 0, nil...) // test case for #18268 var _ = f8[int, float64](0, 0, nil...) // test case for #18268
// init functions cannot have type parameters // init functions cannot have type parameters
@ -271,7 +271,7 @@ type A[T any] T
func (a A[T]) m() A[T] func (a A[T]) m() A[T]
func _[T any]() { func _[T any]() {
f12(A[T])() f12[A[T]]()
} }
// method expressions // method expressions

View File

@ -208,21 +208,28 @@ func isubst(x ast.Expr, smap map[*ast.Ident]*ast.Ident) ast.Expr {
new.X = X new.X = X
return &new return &new
} }
case *ast.CallExpr: case *ast.IndexExpr:
var args []ast.Expr index := isubst(n.Index, smap)
for i, arg := range n.Args { if index != n.Index {
new := isubst(arg, smap) new := *n
if new != arg { new.Index = index
if args == nil { return &new
args = make([]ast.Expr, len(n.Args)) }
copy(args, n.Args) case *ast.ListExpr:
var elems []ast.Expr
for i, elem := range n.ElemList {
new := isubst(elem, smap)
if new != elem {
if elems == nil {
elems = make([]ast.Expr, len(n.ElemList))
copy(elems, n.ElemList)
} }
args[i] = new elems[i] = new
} }
} }
if args != nil { if elems != nil {
new := *n new := *n
new.Args = args new.ElemList = elems
return &new return &new
} }
case *ast.ParenExpr: case *ast.ParenExpr:
@ -460,14 +467,7 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
} }
case *ast.IndexExpr: case *ast.IndexExpr:
return check.instantiatedType(e.X, []ast.Expr{e.Index}, def) return check.instantiatedType(e.X, unpackExpr(e.Index), def)
case *ast.CallExpr:
if e.Brackets {
return check.instantiatedType(e.Fun, e.Args, def)
} else {
check.errorf(e0, _NotAType, "%s is not a type", e0)
}
case *ast.ParenExpr: case *ast.ParenExpr:
// Generic types must be instantiated before they can be used in any form. // Generic types must be instantiated before they can be used in any form.
@ -1158,10 +1158,6 @@ func embeddedFieldIdent(e ast.Expr) *ast.Ident {
return e.Sel return e.Sel
case *ast.IndexExpr: case *ast.IndexExpr:
return embeddedFieldIdent(e.X) return embeddedFieldIdent(e.X)
case *ast.CallExpr:
if e.Brackets {
return embeddedFieldIdent(e.Fun)
}
} }
return nil // invalid embedded field return nil // invalid embedded field
} }