go/types: steps towards type-checking of methods with parameterized receivers

Change-Id: I80b4d4c248cb5e29933366322cca1d76c3ed5e23
This commit is contained in:
Robert Griesemer 2019-07-18 21:29:24 -07:00
parent 0ffe62a473
commit be88be6e7a
5 changed files with 27 additions and 24 deletions

View File

@ -659,10 +659,20 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
// func declarations cannot use iota
assert(check.iota == nil)
if obj.IsParameterized() {
assert(obj.scope != nil)
check.scope = obj.scope // push type parameter scope
}
sig := new(Signature)
obj.typ = sig // guard against cycles
fdecl := decl.fdecl
check.funcType(sig, fdecl.Recv, obj.scope, obj.tparams, fdecl.Type)
check.funcType(sig, fdecl.Recv, fdecl.Type)
sig.tparams = obj.tparams
if obj.IsParameterized() {
check.closeScope()
}
// function body must be type-checked after global declarations
// (functions implemented elsewhere have no body)

View File

@ -338,6 +338,9 @@ func (obj *Func) FullName() string {
// Scope returns the scope of the function's body block.
func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
// IsParameterized reports whether obj is a parameterized function.
func (obj *Func) IsParameterized() bool { return len(obj.tparams) > 0 }
func (*Func) isDependency() {} // a function may be a dependency of an initialization expression
// A Label represents a declared label.

View File

@ -6,14 +6,11 @@ package p
type List(type E) []E
func f(type P) (x P) List(P) {
return List(P){x}
/*
func (l List(E)) First() E {
if len(l) == 0 {
panic("no first")
}
return l[0]
}
var (
_ []int = f(0)
_ []float32 = f(float32)(10)
_ [](List(int)) = f(List(int){})
_ List(List(int)) = [](List(int)){}
_ = [](List(int)){}
)
*/

View File

@ -199,8 +199,9 @@ type Signature struct {
// and store it in the Func Object) because when type-checking a function
// literal we call the general type checker which returns a general Type.
// We then unpack the *Signature and use the scope for the literal body.
scope *Scope // function scope, present for package-local signatures
recv *Var // nil if not a method
scope *Scope // function scope, present for package-local signatures
recv *Var // nil if not a method
// TODO(gri) do we need to keep tparams in the signature?
tparams []*TypeName // type parameters from left to right; or nil
params *Tuple // (incoming) parameters from left to right; or nil
results *Tuple // (outgoing) results from left to right; or nil

View File

@ -157,15 +157,8 @@ func (check *Checker) instantiatedType(e ast.Expr) Type {
}
// funcType type-checks a function or method type.
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
if tparams != nil {
check.scope = scope
// TODO(gri) push/pop both (type parameter and function) scopes
// defer check.closeScope()
}
scope = NewScope(check.scope, token.NoPos, token.NoPos, "function")
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
// TODO(gri) should we close this scope?
scope.isFunc = true
check.recordScope(ftyp, scope)
@ -224,7 +217,6 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, scope *Sc
}
sig.scope = scope
sig.tparams = tparams
sig.params = NewTuple(params...)
sig.results = NewTuple(results...)
sig.variadic = variadic
@ -319,7 +311,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, nil, e)
check.funcType(typ, nil, e)
return typ
case *ast.InterfaceType: