mirror of https://github.com/golang/go.git
go/*: move TParams field into ast.FuncType and adjust dependencies
This step further consolidates all parameter types (except for the receiver) in an ast.FuncType which now matches more closely the representation of a types.Signature. As a result, fewer parameters need to passed around because we can just use an *ast.FuncType or a *types.Signature instead. As an immediate (and implicit) consequence, parameterized interface methods now type-check. (But we cannot yet "implement" them with a matching concrete type.) Change-Id: I2ea24694ade9838488625ffec48d5e98070d1006
This commit is contained in:
parent
e3a0a7429a
commit
32c4c5a5f8
|
|
@ -435,6 +435,7 @@ type (
|
|||
// A FuncType node represents a function type.
|
||||
FuncType struct {
|
||||
Func token.Pos // position of "func" keyword (token.NoPos if there is no "func")
|
||||
TParams *FieldList // type parameters; or nil
|
||||
Params *FieldList // (incoming) parameters; non-nil
|
||||
Results *FieldList // (outgoing) results; or nil
|
||||
}
|
||||
|
|
@ -994,12 +995,11 @@ type (
|
|||
|
||||
// A FuncDecl node represents a function declaration.
|
||||
FuncDecl struct {
|
||||
Doc *CommentGroup // associated documentation; or nil
|
||||
Recv *FieldList // receiver (methods); or nil (functions)
|
||||
Name *Ident // function/method name
|
||||
TParams *FieldList // type parameters; or nil
|
||||
Type *FuncType // function signature: parameters, results, and position of "func" keyword
|
||||
Body *BlockStmt // function body; or nil for external (non-Go) function
|
||||
Doc *CommentGroup // associated documentation; or nil
|
||||
Recv *FieldList // receiver (methods); or nil (functions)
|
||||
Name *Ident // function/method name
|
||||
Type *FuncType // function signature: type and value parameters, results, and position of "func" keyword
|
||||
Body *BlockStmt // function body; or nil for external (non-Go) function
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1134,9 +1134,9 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
|
|||
// method
|
||||
idents = []*ast.Ident{ident}
|
||||
scope := ast.NewScope(nil) // method scope
|
||||
_, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method")
|
||||
tparams, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method")
|
||||
results := p.parseResult(scope, true)
|
||||
typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
|
||||
typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
|
||||
} else {
|
||||
// embedded interface
|
||||
typ = x
|
||||
|
|
@ -1256,9 +1256,9 @@ func (p *parser) parseConstraint() *ast.Constraint {
|
|||
// method
|
||||
mname = ident
|
||||
scope := ast.NewScope(nil) // method scope
|
||||
_, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method")
|
||||
tparams, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method")
|
||||
results := p.parseResult(scope, true)
|
||||
typ = &ast.FuncType{Func: token.NoPos, Params: params, Results: results}
|
||||
typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
|
||||
}
|
||||
mnames = append(mnames, mname)
|
||||
types = append(types, typ)
|
||||
|
|
@ -2807,12 +2807,12 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
|
|||
}
|
||||
|
||||
decl := &ast.FuncDecl{
|
||||
Doc: doc,
|
||||
Recv: recv,
|
||||
Name: ident,
|
||||
TParams: tparams,
|
||||
Doc: doc,
|
||||
Recv: recv,
|
||||
Name: ident,
|
||||
Type: &ast.FuncType{
|
||||
Func: pos,
|
||||
TParams: tparams,
|
||||
Params: params,
|
||||
Results: results,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -384,22 +384,26 @@ func (p *printer) parameters(isTypeParam bool, fields *ast.FieldList) {
|
|||
p.print(fields.Closing, token.RPAREN)
|
||||
}
|
||||
|
||||
func (p *printer) signature(params, result *ast.FieldList) {
|
||||
if params != nil {
|
||||
p.parameters(false, params)
|
||||
func (p *printer) signature(sig *ast.FuncType) {
|
||||
if sig.TParams != nil {
|
||||
p.parameters(true, sig.TParams)
|
||||
}
|
||||
if sig.Params != nil {
|
||||
p.parameters(false, sig.Params)
|
||||
} else {
|
||||
p.print(token.LPAREN, token.RPAREN)
|
||||
}
|
||||
n := result.NumFields()
|
||||
res := sig.Results
|
||||
n := res.NumFields()
|
||||
if n > 0 {
|
||||
// result != nil
|
||||
// res != nil
|
||||
p.print(blank)
|
||||
if n == 1 && result.List[0].Names == nil {
|
||||
// single anonymous result; no ()'s
|
||||
p.expr(stripParensAlways(result.List[0].Type))
|
||||
if n == 1 && res.List[0].Names == nil {
|
||||
// single anonymous res; no ()'s
|
||||
p.expr(stripParensAlways(res.List[0].Type))
|
||||
return
|
||||
}
|
||||
p.parameters(false, result)
|
||||
p.parameters(false, res)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -472,7 +476,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
|
|||
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
|
||||
// method
|
||||
p.expr(f.Names[0])
|
||||
p.signature(ftyp.Params, ftyp.Results)
|
||||
p.signature(ftyp)
|
||||
} else {
|
||||
// embedded interface
|
||||
p.expr(f.Type)
|
||||
|
|
@ -549,7 +553,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
|
|||
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
|
||||
// method
|
||||
p.expr(f.Names[0])
|
||||
p.signature(ftyp.Params, ftyp.Results)
|
||||
p.signature(ftyp)
|
||||
} else {
|
||||
// embedded interface
|
||||
p.expr(f.Type)
|
||||
|
|
@ -802,7 +806,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
|
|||
p.print(x.Type.Pos(), token.FUNC)
|
||||
// See the comment in funcDecl about how the header size is computed.
|
||||
startCol := p.out.Column - len("func")
|
||||
p.signature(x.Type.Params, x.Type.Results)
|
||||
p.signature(x.Type)
|
||||
p.funcBody(p.distanceFrom(x.Type.Pos(), startCol), blank, x.Body)
|
||||
|
||||
case *ast.ParenExpr:
|
||||
|
|
@ -947,7 +951,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
|
|||
|
||||
case *ast.FuncType:
|
||||
p.print(token.FUNC)
|
||||
p.signature(x.Params, x.Results)
|
||||
p.signature(x)
|
||||
|
||||
case *ast.InterfaceType:
|
||||
p.print(token.INTERFACE)
|
||||
|
|
@ -1075,7 +1079,7 @@ func (p *printer) constraint(x *ast.Constraint) {
|
|||
for i, m := range x.MNames {
|
||||
p.print(m)
|
||||
t := x.Types[i].(*ast.FuncType)
|
||||
p.signature(t.Params, t.Results)
|
||||
p.signature(t)
|
||||
//p.print(token.COMMA)
|
||||
}
|
||||
}
|
||||
|
|
@ -1821,10 +1825,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
|
|||
p.print(blank)
|
||||
}
|
||||
p.expr(d.Name)
|
||||
if d.TParams != nil {
|
||||
p.parameters(true, d.TParams)
|
||||
}
|
||||
p.signature(d.Type.Params, d.Type.Results)
|
||||
p.signature(d.Type)
|
||||
p.funcBody(p.distanceFrom(d.Pos(), startCol), vtab, d.Body)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
|
|||
saved := obj.color_
|
||||
obj.color_ = black
|
||||
fdecl := decl.fdecl
|
||||
check.funcType(sig, fdecl.Recv, fdecl.TParams, fdecl.Type)
|
||||
check.funcType(sig, fdecl.Recv, fdecl.Type)
|
||||
obj.color_ = saved
|
||||
|
||||
// function body must be type-checked after global declarations
|
||||
|
|
|
|||
|
|
@ -415,8 +415,8 @@ func (check *Checker) collectObjects() {
|
|||
// treat as function
|
||||
}
|
||||
if name == "init" {
|
||||
if d.TParams != nil {
|
||||
check.softErrorf(d.TParams.Pos(), "func init must have no type parameters")
|
||||
if d.Type.TParams != nil {
|
||||
check.softErrorf(d.Type.TParams.Pos(), "func init must have no type parameters")
|
||||
}
|
||||
if t := d.Type; t.Params.NumFields() != 0 || t.Results != nil {
|
||||
check.softErrorf(d.Pos(), "func init must have no arguments and no return values")
|
||||
|
|
@ -435,8 +435,8 @@ func (check *Checker) collectObjects() {
|
|||
} else {
|
||||
// method
|
||||
// d.Recv != nil && len(d.Recv.List) > 0
|
||||
if !methodTypeParamsOk && d.TParams != nil {
|
||||
check.invalidAST(d.TParams.Pos(), "method must have no type parameters")
|
||||
if !methodTypeParamsOk && d.Type.TParams != nil {
|
||||
check.invalidAST(d.Type.TParams.Pos(), "method must have no type parameters")
|
||||
}
|
||||
ptr, recv, _ := check.unpackRecv(d.Recv.List[0].Type, false)
|
||||
// (Methods with invalid receiver cannot be associated to a type, and
|
||||
|
|
|
|||
|
|
@ -4,4 +4,13 @@
|
|||
|
||||
package p
|
||||
|
||||
type S(type T) struct{}; func (S) _()
|
||||
type I interface{
|
||||
m(type T)(T)
|
||||
}
|
||||
|
||||
type S struct{}
|
||||
|
||||
func (S) m(type T)(T)
|
||||
|
||||
// TODO(gri) this should work
|
||||
var _ I = S /* ERROR wrong type for method m */ {}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ func (check *Checker) genericType(e ast.Expr, reportErr bool) Type {
|
|||
}
|
||||
|
||||
// funcType type-checks a function or method type.
|
||||
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftparams *ast.FieldList, ftyp *ast.FuncType) {
|
||||
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
|
||||
check.openScope(ftyp, "function")
|
||||
check.scope.isFunc = true
|
||||
check.recordScope(ftyp, check.scope)
|
||||
|
|
@ -214,8 +214,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftparams
|
|||
}
|
||||
}
|
||||
|
||||
if ftparams != nil {
|
||||
sig.tparams = check.collectTypeParams(ftparams)
|
||||
if ftyp.TParams != nil {
|
||||
sig.tparams = check.collectTypeParams(ftyp.TParams)
|
||||
}
|
||||
|
||||
// Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their
|
||||
|
|
@ -391,7 +391,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) (T Type) {
|
|||
case *ast.FuncType:
|
||||
typ := new(Signature)
|
||||
def.setUnderlying(typ)
|
||||
check.funcType(typ, nil, nil, e)
|
||||
check.funcType(typ, nil, e)
|
||||
return typ
|
||||
|
||||
case *ast.InterfaceType:
|
||||
|
|
|
|||
Loading…
Reference in New Issue