mirror of https://github.com/golang/go.git
go/types: set receiver type bounds for methods
Enable a few more tests that now work correctly. Change-Id: I7efe91660c2896d4d8279b86831aa7de2ae7c0ad
This commit is contained in:
parent
d49c915592
commit
2aeeba6836
|
|
@ -730,15 +730,41 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
|
|||
|
||||
fdecl := decl.fdecl
|
||||
if fdecl.IsMethod() {
|
||||
_, _, tparams := check.unpackRecv(fdecl.Recv.List[0].Type, true)
|
||||
_, rname, tparams := check.unpackRecv(fdecl.Recv.List[0].Type, true)
|
||||
if len(tparams) > 0 {
|
||||
// TODO(gri) need to provide contract
|
||||
// (check that number of parameters match is done when type-checking the receiver expression)
|
||||
// declare the method's receiver type parameters
|
||||
check.openScope(fdecl, "receiver type parameters")
|
||||
defer check.closeScope()
|
||||
// TODO(gri) can we use (an adjusted version of) collectTypeParams here?
|
||||
for i, name := range tparams {
|
||||
obj.tparams = append(obj.tparams, check.declareTypeParam(name, i, nil))
|
||||
// collect and declare the type parameters
|
||||
var list []Type // list of corresponding *TypeParams
|
||||
for index, name := range tparams {
|
||||
tpar := check.declareTypeParam(name, index, nil)
|
||||
obj.tparams = append(obj.tparams, tpar)
|
||||
list = append(list, tpar.typ)
|
||||
}
|
||||
// determine receiver type to get its type parameters
|
||||
// and the respective type parameter bounds
|
||||
var recvTParams []*TypeName
|
||||
if rname != nil {
|
||||
// recv should be a Named type (otherwise an error is reported elsewhere)
|
||||
if recv, _ := check.genericType(rname).(*Named); recv != nil {
|
||||
recvTParams = recv.obj.tparams
|
||||
}
|
||||
}
|
||||
// provide type parameter bounds
|
||||
// - only do this if we have the right number (otherwise an error is reported elsewhere)
|
||||
if len(list) == len(recvTParams) {
|
||||
assert(len(list) == len(obj.tparams))
|
||||
for index, tname := range obj.tparams {
|
||||
bound := recvTParams[index].typ.(*TypeParam).bound
|
||||
// bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the
|
||||
// current context.
|
||||
if bound != nil {
|
||||
bound = check.subst(tname.pos, bound, recvTParams, list)
|
||||
tname.typ.(*TypeParam).bound = bound
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if fdecl.TParams != nil {
|
||||
|
|
|
|||
|
|
@ -43,17 +43,17 @@ contract G(Node, Edge) {
|
|||
|
||||
type Graph (type Node, Edge G) struct { /* ... */ }
|
||||
|
||||
func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge) { panic("unimplemented") }
|
||||
func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge)
|
||||
|
||||
// func (g *Graph(N, E)) ShortestPath(from, to N) []E { panic("unimplemented") }
|
||||
func (g *Graph(N, E)) ShortestPath(from, to N) []E
|
||||
|
||||
// Same Graph using interface bounds instead of a contract.
|
||||
|
||||
type AltGraph (type Node NodeFace(Edge), Edge EdgeFace(Node)) struct { }
|
||||
|
||||
func AltNew (type Node NodeFace(Edge), Edge EdgeFace(Node)) (nodes []Node) *AltGraph(Node, Edge) { panic("unimplemented") }
|
||||
func AltNew (type Node NodeFace(Edge), Edge EdgeFace(Node)) (nodes []Node) *AltGraph(Node, Edge)
|
||||
|
||||
// func (g *AltGraph(N, E)) ShortestPath(from, to N) []E { panic("unimplemented") }
|
||||
func (g *AltGraph(N, E)) ShortestPath(from, to N) []E
|
||||
|
||||
type NodeFace(type Edge) interface {
|
||||
Edges() []Edge
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ func (check *Checker) collectObjects() {
|
|||
// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its
|
||||
// type parameters, if any. The type parameters are only unpacked if unpackParams is
|
||||
// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we
|
||||
// cannot easily work aound with).
|
||||
// cannot easily work around).
|
||||
func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) {
|
||||
L: // unpack receiver type
|
||||
for {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
// determine type parameter bound
|
||||
iface := tpar.Interface()
|
||||
|
||||
// TODO(gri) document/explain why the substitution below is correct
|
||||
//check.dump(">>> %s: iface before: %s", pos, iface)
|
||||
bound := check.subst(pos, tpar.bound, tparams, targs).Underlying()
|
||||
switch b := bound.(type) {
|
||||
|
|
@ -102,6 +103,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
if targ, _ := targ.Underlying().(*TypeParam); targ != nil {
|
||||
for _, t := range targ.Interface().types {
|
||||
if !includesType(t, iface) {
|
||||
// TODO(gri) match this error message with the one below (or vice versa)
|
||||
check.softErrorf(pos, "%s does not satisfy %s (missing type %s)", targ, tpar.bound, t)
|
||||
break
|
||||
}
|
||||
|
|
@ -123,6 +125,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
}
|
||||
|
||||
// includesType reports whether iface includes typ
|
||||
// TODO(gri) make this a method of *Interface
|
||||
func includesType(typ Type, iface *Interface) bool {
|
||||
for _, t := range iface.types {
|
||||
if Identical(typ.Underlying(), t) {
|
||||
|
|
@ -139,13 +142,28 @@ func (check *Checker) subst(pos token.Pos, typ Type, tpars []*TypeName, targs []
|
|||
if len(tpars) == 0 {
|
||||
return typ
|
||||
}
|
||||
subst := subster{pos, check, make(map[Type]Type), tpars, targs}
|
||||
|
||||
// common cases
|
||||
switch t := typ.(type) {
|
||||
case *Basic:
|
||||
return typ // nothing to do
|
||||
case *TypeParam:
|
||||
for i, tpar := range tpars {
|
||||
if tpar.typ == t {
|
||||
return targs[i]
|
||||
}
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// general case
|
||||
subst := subster{check, pos, make(map[Type]Type), tpars, targs}
|
||||
return subst.typ(typ)
|
||||
}
|
||||
|
||||
type subster struct {
|
||||
pos token.Pos
|
||||
check *Checker
|
||||
pos token.Pos
|
||||
cache map[Type]Type
|
||||
tpars []*TypeName
|
||||
targs []Type
|
||||
|
|
@ -303,6 +321,9 @@ func (subst *subster) typ(typ Type) Type {
|
|||
}
|
||||
}
|
||||
|
||||
case *Contract:
|
||||
panic("unimplemented")
|
||||
|
||||
default:
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ func (check *Checker) definedType(e ast.Expr, def *Named) Type {
|
|||
return typ
|
||||
}
|
||||
|
||||
// generic us like typ bit the type must be an (uninstantiated) generic type.
|
||||
// generic is like typ but the type must be an (uninstantiated) generic type.
|
||||
func (check *Checker) genericType(e ast.Expr) Type {
|
||||
typ := check.typInternal(e, nil)
|
||||
assert(isTyped(typ))
|
||||
|
|
|
|||
Loading…
Reference in New Issue