From be88be6e7a24cfa888b3fd5c81b8a51a70240d9f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 18 Jul 2019 21:29:24 -0700 Subject: [PATCH] go/types: steps towards type-checking of methods with parameterized receivers Change-Id: I80b4d4c248cb5e29933366322cca1d76c3ed5e23 --- src/go/types/decl.go | 12 +++++++++++- src/go/types/object.go | 3 +++ src/go/types/testdata/tmp.go2 | 17 +++++++---------- src/go/types/type.go | 5 +++-- src/go/types/typexpr.go | 14 +++----------- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 70f36d826e..d2361e1842 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -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) diff --git a/src/go/types/object.go b/src/go/types/object.go index f0db9fbaad..30db273935 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -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. diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index 7c694dd9b0..f43cdc68c6 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -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)){} -) +*/ \ No newline at end of file diff --git a/src/go/types/type.go b/src/go/types/type.go index 43570a0a18..fb9e74c8a4 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -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 diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 320390fd2d..15f342d3c4 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -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: