mirror of https://github.com/golang/go.git
go/types: collect function type parameters during resolve phase
- move init and method parameter checks to resolve phase as well - more consistent error messages - more tests Change-Id: I6cb147b35385541ca5d7d7e3f87159df84cced76
This commit is contained in:
parent
db132013f4
commit
fa30b485bc
|
|
@ -660,11 +660,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
|
|||
sig := new(Signature)
|
||||
obj.typ = sig // guard against cycles
|
||||
fdecl := decl.fdecl
|
||||
check.funcType(sig, fdecl.Recv, fdecl.TParams, fdecl.Type)
|
||||
if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
|
||||
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
|
||||
// ok to continue
|
||||
}
|
||||
check.funcType(sig, fdecl.Recv, obj.scope, obj.tparams, fdecl.Type)
|
||||
|
||||
// function body must be type-checked after global declarations
|
||||
// (functions implemented elsewhere have no body)
|
||||
|
|
@ -787,7 +783,9 @@ func (check *Checker) declStmt(decl ast.Decl) {
|
|||
|
||||
case *ast.TypeSpec:
|
||||
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
||||
obj.scope, obj.tparams = check.collectTypeParams(check.scope, s, s.TParams)
|
||||
if s.TParams != nil {
|
||||
obj.scope, obj.tparams = check.collectTypeParams(check.scope, s, s.TParams)
|
||||
}
|
||||
// spec: "The scope of a type identifier declared inside a function
|
||||
// begins at the identifier in the TypeSpec and ends at the end of
|
||||
// the innermost containing block."
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ func (*Const) isDependency() {} // a constant may be a dependency of an initiali
|
|||
// A TypeName represents a name for a (defined or alias) type.
|
||||
type TypeName struct {
|
||||
object
|
||||
// TODO(gri) For Funcs, we have the type parameters on the signature. Revisit that decision.
|
||||
scope *Scope // type parameter scope; or nil
|
||||
tparams []*TypeName // type parameters from left to right; or nil
|
||||
}
|
||||
|
|
@ -301,7 +300,9 @@ func (*Var) isDependency() {} // a variable may be a dependency of an initializa
|
|||
// An abstract method may belong to many interfaces due to embedding.
|
||||
type Func struct {
|
||||
object
|
||||
hasPtrRecv bool // only valid for methods that don't have a type yet
|
||||
hasPtrRecv bool // only valid for methods that don't have a type yet
|
||||
scope *Scope // type parameter scope; or nil
|
||||
tparams []*TypeName // type parameters from left to right; or nil
|
||||
}
|
||||
|
||||
// NewFunc returns a new function with the given signature, representing
|
||||
|
|
@ -312,7 +313,7 @@ func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
|
|||
if sig != nil {
|
||||
typ = sig
|
||||
}
|
||||
return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false}
|
||||
return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, false, nil, nil}
|
||||
}
|
||||
|
||||
// FullName returns the package- or receiver-type-qualified name of
|
||||
|
|
|
|||
|
|
@ -215,6 +215,7 @@ func (check *Checker) collectObjects() {
|
|||
}
|
||||
|
||||
var methods []*Func // list of methods with non-blank _ names
|
||||
var fileScopes []*Scope
|
||||
for fileNo, file := range check.files {
|
||||
// The package identifier denotes the current package,
|
||||
// but there is no corresponding package object.
|
||||
|
|
@ -228,6 +229,7 @@ func (check *Checker) collectObjects() {
|
|||
pos, end = token.Pos(f.Base()), token.Pos(f.Base()+f.Size())
|
||||
}
|
||||
fileScope := NewScope(check.pkg.scope, pos, end, check.filename(fileNo))
|
||||
fileScopes = append(fileScopes, fileScope)
|
||||
check.recordScope(file, fileScope)
|
||||
|
||||
// determine file directory, necessary to resolve imports
|
||||
|
|
@ -386,7 +388,9 @@ func (check *Checker) collectObjects() {
|
|||
|
||||
case *ast.TypeSpec:
|
||||
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
|
||||
obj.scope, obj.tparams = check.collectTypeParams(pkg.scope, s, s.TParams)
|
||||
if s.TParams != nil {
|
||||
obj.scope, obj.tparams = check.collectTypeParams(pkg.scope, s, s.TParams)
|
||||
}
|
||||
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
|
||||
|
||||
default:
|
||||
|
|
@ -400,18 +404,32 @@ func (check *Checker) collectObjects() {
|
|||
if d.Recv == nil {
|
||||
// regular function
|
||||
if name == "init" {
|
||||
if d.TParams != nil {
|
||||
check.softErrorf(d.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")
|
||||
}
|
||||
// don't declare init functions in the package scope - they are invisible
|
||||
obj.parent = pkg.scope
|
||||
check.recordDef(d.Name, obj)
|
||||
// init functions must have a body
|
||||
if d.Body == nil {
|
||||
// TODO(gri) make this error message consistent with the others above
|
||||
check.softErrorf(obj.pos, "missing function body")
|
||||
}
|
||||
} else {
|
||||
if d.TParams != nil {
|
||||
obj.scope, obj.tparams = check.collectTypeParams(pkg.scope, d, d.TParams)
|
||||
}
|
||||
check.declare(pkg.scope, d.Name, obj, token.NoPos)
|
||||
}
|
||||
} else {
|
||||
// method
|
||||
if d.TParams != nil {
|
||||
// TODO(gri) should this be done in the parser (and this an invalidAST error)?
|
||||
check.softErrorf(d.TParams.Pos(), "method must have no type parameters")
|
||||
}
|
||||
// (Methods with blank _ names are never found; no need to collect
|
||||
// them for later type association. They will still be type-checked
|
||||
// with all the other functions.)
|
||||
|
|
@ -435,7 +453,7 @@ func (check *Checker) collectObjects() {
|
|||
}
|
||||
|
||||
// verify that objects in package and file scopes have different names
|
||||
for _, scope := range check.pkg.scope.children /* file scopes */ {
|
||||
for _, scope := range fileScopes {
|
||||
for _, obj := range scope.elems {
|
||||
if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
|
||||
if pkg, ok := obj.(*PkgName); ok {
|
||||
|
|
@ -473,10 +491,6 @@ func (check *Checker) collectObjects() {
|
|||
}
|
||||
|
||||
func (check *Checker) collectTypeParams(parent *Scope, node ast.Node, list *ast.FieldList) (scope *Scope, tparams []*TypeName) {
|
||||
if list.NumFields() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
scope = NewScope(parent, node.Pos(), node.End(), "type parameters")
|
||||
check.recordScope(node, scope)
|
||||
|
||||
|
|
|
|||
|
|
@ -111,3 +111,15 @@ 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)(0, 0, nil...) // test case for #18268
|
||||
|
||||
// init function and methods cannot have type parameters
|
||||
|
||||
func init() {}
|
||||
func init(/* ERROR func init must have no type parameters */ type)() {}
|
||||
func init(/* ERROR func init must have no type parameters */ type P)() {}
|
||||
|
||||
type T struct {}
|
||||
|
||||
func (T) m1() {}
|
||||
func (T) m2( /* ERROR method must have no type parameters */ type)() {}
|
||||
func (T) m3( /* ERROR method must have no type parameters */ type P)() {}
|
||||
|
|
|
|||
|
|
@ -143,13 +143,11 @@ func (check *Checker) definedType(e ast.Expr, def *Named) (T Type) {
|
|||
}
|
||||
|
||||
// funcType type-checks a function or method type.
|
||||
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, tpar *ast.FieldList, ftyp *ast.FuncType) {
|
||||
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, scope *Scope, tparams []*TypeName, ftyp *ast.FuncType) {
|
||||
// type parameters are in a scope enclosing the function scope
|
||||
// TODO(gri) get rid of fake ast.Ident - only here to satisfy collectTypeParams
|
||||
scope, tparams := check.collectTypeParams(check.scope, new(ast.Ident), tpar)
|
||||
if scope != nil {
|
||||
// TODO(gri) push/pop both (type parameter and function) scopes
|
||||
if tparams != nil {
|
||||
check.scope = scope
|
||||
// TODO(gri) push/pop both (type parameter and function) scopes
|
||||
// defer check.closeScope()
|
||||
}
|
||||
|
||||
|
|
@ -209,10 +207,6 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, tpar *ast
|
|||
}
|
||||
}
|
||||
sig.recv = recv
|
||||
// A method cannot have type parameters - this should be checked by the parser.
|
||||
if len(tparams) > 0 {
|
||||
check.invalidAST(tpar.Pos(), "method cannot have type parameters")
|
||||
}
|
||||
}
|
||||
|
||||
sig.scope = scope
|
||||
|
|
@ -301,7 +295,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
|||
case *ast.FuncType:
|
||||
typ := new(Signature)
|
||||
def.setUnderlying(typ)
|
||||
check.funcType(typ, nil, nil, e)
|
||||
check.funcType(typ, nil, nil, nil, e)
|
||||
return typ
|
||||
|
||||
case *ast.InterfaceType:
|
||||
|
|
|
|||
Loading…
Reference in New Issue