go/types: initial steps towards customizing method signatures

Needs more work and tests.

Change-Id: Ic54e5798c374254d55b46cb582d7cf87efe125d1
This commit is contained in:
Robert Griesemer 2019-07-21 22:40:33 -07:00
parent 3663c91f3a
commit e2ccf6356b
5 changed files with 21 additions and 10 deletions

View File

@ -319,7 +319,7 @@ type Func struct {
// NewFunc returns a new function with the given signature, representing
// the function's type.
func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
// don't store a nil signature
// don't store a (typed) nil signature
var typ Type
if sig != nil {
typ = sig

View File

@ -90,7 +90,9 @@ func (s *subster) typ(typ Type) (res Type) {
return s.tuple(t)
case *Signature:
recv := s.var_(t.recv) // not strictly needed (receivers cannot be parametrized)
// TODO(gri) rethink the recv situation with respect to methods on parameterized types
//recv := s.var_(t.recv) // not strictly needed (receivers cannot be parameterized) (?)
recv := t.recv
params := s.tuple(t.params)
results := s.tuple(t.results)
if recv != t.recv || params != t.params || results != t.results {
@ -123,19 +125,26 @@ func (s *subster) typ(typ Type) (res Type) {
if underlying != t.underlying {
// create a new named type - for now use printed type in name
// TODO(gri) consider type map to map types to indices (on the other hand, a type string seems just as good)
if len(t.methods) > 0 {
panic("cannot handle instantiation of types with methods yet")
}
// TODO(gri) review name creation and factor out
name := TypeString(t, nil) + "<" + typeListString(s.targs) + ">"
//s.check.dump("NAME = %s", name)
tname, found := s.check.typMap[name]
if !found {
// instantiate custom methods as necessary
var methods []*Func
for _, m := range t.methods {
//sig := s.typ(m.typ).(*Signature)
sig := s.check.subst(m.typ, m.tparams, s.targs).(*Signature)
m1 := NewFunc(m.pos, m.pkg, m.name, sig)
//s.check.dump("%s: method %s => %s", name, m, m1)
methods = append(methods, m1)
}
// TODO(gri) what is the correct position to use here?
tname = NewTypeName(t.obj.pos, s.check.pkg, name, nil)
//s.check.dump("name = %s", name)
NewNamed(tname, underlying, nil) // TODO(gri) provide correct method list
NewNamed(tname, underlying, methods)
s.check.typMap[name] = tname
// TODO(gri) update the method receivers?
}
return tname.typ
}

View File

@ -12,5 +12,3 @@ func (l List(E)) First() E {
}
return l[0]
}
// var _ string = List(string){"foo"}.First()

View File

@ -46,4 +46,7 @@ var (
_ [](List(int)) = f(List(int){})
_ List(List(int)) = [](List(int)){}
_ = [](List(int)){}
)
)
// Parameterized types with methods

View File

@ -201,7 +201,8 @@ type Signature struct {
// 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
// TODO(gri) do we need to keep tparams in the signature?
// TODO(gri) do we need to keep tparams in the Signature, rather than the Func object?
// (how are they different from type parameters which we keep with the TypeName?)
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