diff --git a/src/go/types/object.go b/src/go/types/object.go index 30db273935..1c6322c6be 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -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 diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 19c657fc64..3ac1ad3a30 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -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 } diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index bca1410297..afd7803259 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -12,5 +12,3 @@ func (l List(E)) First() E { } return l[0] } - -// var _ string = List(string){"foo"}.First() \ No newline at end of file diff --git a/src/go/types/testdata/typeinst2.go2 b/src/go/types/testdata/typeinst2.go2 index 15a83a1251..518a15d06d 100644 --- a/src/go/types/testdata/typeinst2.go2 +++ b/src/go/types/testdata/typeinst2.go2 @@ -46,4 +46,7 @@ var ( _ [](List(int)) = f(List(int){}) _ List(List(int)) = [](List(int)){} _ = [](List(int)){} -) \ No newline at end of file +) + +// Parameterized types with methods + diff --git a/src/go/types/type.go b/src/go/types/type.go index fb9e74c8a4..319faace39 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -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