mirror of https://github.com/golang/go.git
go/types: collect type parameters of types and set up corresponding scopes
Change-Id: Ie63ffcdb8e3682b75f9863cea7987561772e6809
This commit is contained in:
parent
aa0fabb90e
commit
db132013f4
|
|
@ -101,7 +101,7 @@ var tests = [][]string{
|
|||
|
||||
// Go 2 tests (type parameters and contracts)
|
||||
{"testdata/typeparams.go2"},
|
||||
//{"testdata/typeinst.go2"},
|
||||
{"testdata/typeinst.go2"},
|
||||
{"testdata/contracts.go2"},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -546,6 +546,11 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
|
|||
check.validType(obj.typ, nil)
|
||||
})
|
||||
|
||||
if obj.IsParametrized() {
|
||||
assert(obj.scope != nil)
|
||||
check.scope = obj.scope // push type parameter scope
|
||||
}
|
||||
|
||||
if tdecl.Assign.IsValid() {
|
||||
// type alias declaration
|
||||
|
||||
|
|
@ -579,6 +584,10 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
|
|||
|
||||
}
|
||||
|
||||
if obj.IsParametrized() {
|
||||
check.closeScope()
|
||||
}
|
||||
|
||||
check.addMethodDecls(obj)
|
||||
}
|
||||
|
||||
|
|
@ -778,6 +787,7 @@ 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)
|
||||
// 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,6 +213,9 @@ 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
|
||||
}
|
||||
|
||||
// NewTypeName returns a new type name denoting the given typ.
|
||||
|
|
@ -223,7 +226,12 @@ type TypeName struct {
|
|||
// argument for NewNamed, which will set the TypeName's type as a side-
|
||||
// effect.
|
||||
func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
|
||||
return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}}
|
||||
return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, nil, nil}
|
||||
}
|
||||
|
||||
// IsParametrized reports whether obj is a parametrized type.
|
||||
func (obj *TypeName) IsParametrized() bool {
|
||||
return len(obj.tparams) > 0
|
||||
}
|
||||
|
||||
// IsAlias reports whether obj is an alias name for a type.
|
||||
|
|
|
|||
|
|
@ -386,6 +386,7 @@ 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)
|
||||
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
|
||||
|
||||
default:
|
||||
|
|
@ -471,6 +472,28 @@ 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)
|
||||
|
||||
index := 0
|
||||
for _, f := range list.List {
|
||||
for _, name := range f.Names {
|
||||
tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
|
||||
NewTypeParam(tpar, index) // assigns type to tpar as a side-effect
|
||||
check.declare(scope, name, tpar, scope.pos)
|
||||
tparams = append(tparams, tpar)
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// resolveBaseTypeName returns the non-alias base type name for typ, and whether
|
||||
// there was a pointer indirection to get to it. The base type name must be declared
|
||||
// in package scope, and there can be at most one pointer indirection. If no such type
|
||||
|
|
|
|||
|
|
@ -145,19 +145,20 @@ 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) {
|
||||
// type parameters are in a scope enclosing the function scope
|
||||
// TODO(gri) should we always have this extra scope?
|
||||
if tpar.NumFields() != 0 {
|
||||
check.scope = NewScope(check.scope, token.NoPos, token.NoPos, "function type parameters") // TODO(gri) replace with check.openScope call
|
||||
defer check.closeScope()
|
||||
// TODO(gri) record this 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
|
||||
check.scope = scope
|
||||
// defer check.closeScope()
|
||||
}
|
||||
scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
|
||||
|
||||
scope = NewScope(check.scope, token.NoPos, token.NoPos, "function")
|
||||
// TODO(gri) should we close this scope?
|
||||
scope.isFunc = true
|
||||
check.recordScope(ftyp, scope)
|
||||
|
||||
recvList, _ := check.collectParams(scope, recvPar, false)
|
||||
tparams := check.collectTypeParams(check.scope, tpar)
|
||||
params, variadic := check.collectParams(scope, ftyp.Params, true)
|
||||
results, _ := check.collectParams(scope, ftyp.Results, false)
|
||||
|
||||
|
|
@ -418,25 +419,6 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
|
|||
return -1
|
||||
}
|
||||
|
||||
func (check *Checker) collectTypeParams(scope *Scope, list *ast.FieldList) (tparams []*TypeName) {
|
||||
if list == nil {
|
||||
return
|
||||
}
|
||||
|
||||
index := 0
|
||||
for _, f := range list.List {
|
||||
for _, name := range f.Names {
|
||||
tpar := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
|
||||
NewTypeParam(tpar, index) // assigns type to tpar as a side-effect
|
||||
check.declare(scope, name, tpar, scope.pos)
|
||||
tparams = append(tparams, tpar)
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
|
||||
if list == nil {
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue