mirror of https://github.com/golang/go.git
go/types: substitute type parameters when checking type param. bounds
Change-Id: Ib97d1b3928629bc073b32fde48709369213a4bbb
This commit is contained in:
parent
d941f3db1d
commit
a30fb05aa2
|
|
@ -5,8 +5,8 @@ TODO
|
|||
- interface embedding doesn't take care of literal type constraints yet
|
||||
(need an allTypes list, like we have an allMethods list?)
|
||||
|
||||
|
||||
OPEN ISSUES
|
||||
- contracts slip through in places where only types are permitted
|
||||
|
||||
|
||||
DESIGN DECISIONS
|
||||
|
|
|
|||
|
|
@ -615,6 +615,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
|
|||
index = 0
|
||||
for _, f := range list.List {
|
||||
var bound Type
|
||||
var isContract bool
|
||||
if f.Type != nil {
|
||||
typ := check.typ(f.Type)
|
||||
if typ != Typ[Invalid] {
|
||||
|
|
@ -628,6 +629,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
|
|||
break // cannot use this contract
|
||||
}
|
||||
bound = typ
|
||||
isContract = true
|
||||
default:
|
||||
check.errorf(f.Type.Pos(), "%s is not an interface or contract", typ)
|
||||
}
|
||||
|
|
@ -636,10 +638,16 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
|
|||
|
||||
// set the type parameter's bound
|
||||
// (do this even if bound == nil to make sure index is correctly increasing)
|
||||
for _, name := range f.Names {
|
||||
for i, name := range f.Names {
|
||||
tname := tparams[index]
|
||||
assert(name.Name == tname.name) // keep - this assertion caught index errors
|
||||
tname.typ.(*TypeParam).bound = bound
|
||||
assert(name.Name == tname.name) // catch index errors
|
||||
// TODO(gri) enable the then branch to force interfaces for all
|
||||
// bounds and unpack the interface in the else branch
|
||||
if false && isContract {
|
||||
tname.typ.(*TypeParam).bound = bound.Underlying().(*Contract).ifaceAt(i)
|
||||
} else {
|
||||
tname.typ.(*TypeParam).bound = bound
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge) { panic("unimplem
|
|||
|
||||
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) { panic("unimplemented") }
|
||||
|
||||
type NodeFace(type Edge) interface {
|
||||
Edges() []Edge
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
return Typ[Invalid]
|
||||
}
|
||||
|
||||
// TODO(gri) should we check for len(tparams) == 0?
|
||||
|
||||
// check bounds
|
||||
for i, tname := range tparams {
|
||||
targ := targs[i]
|
||||
|
|
@ -62,7 +64,7 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
// (keeping it may make sense because it's a common scenario and it may
|
||||
// be more efficient to check)
|
||||
if tpar.bound == nil {
|
||||
continue // no bound (optimization)
|
||||
continue // no type bound (optimization)
|
||||
}
|
||||
|
||||
// best position for error reporting
|
||||
|
|
@ -74,6 +76,16 @@ func (check *Checker) instantiate(pos token.Pos, typ Type, targs []Type, poslist
|
|||
// determine type parameter bound
|
||||
iface := tpar.Interface()
|
||||
|
||||
//check.dump(">>> %s: iface before: %s", pos, iface)
|
||||
bound := check.subst(pos, tpar.bound, tparams, targs).Underlying()
|
||||
switch b := bound.(type) {
|
||||
case *Interface:
|
||||
iface = b
|
||||
case *Contract:
|
||||
iface = b.ifaceAt(i)
|
||||
}
|
||||
//check.dump(">>> %s: iface after : %s", pos, iface)
|
||||
|
||||
// targ must implement iface (methods)
|
||||
if m, _ := check.missingMethod(targ, iface, true); m != nil {
|
||||
check.softErrorf(pos, "%s does not satisfy %s (missing method %s)", targ, tpar.bound, m)
|
||||
|
|
@ -124,7 +136,7 @@ func includesType(typ Type, iface *Interface) bool {
|
|||
// subst returns the type typ with its type parameters tparams replaced by
|
||||
// the corresponding type arguments targs, recursively.
|
||||
func (check *Checker) subst(pos token.Pos, typ Type, tpars []*TypeName, targs []Type) Type {
|
||||
assert(len(tpars) == len(targs)) // bounds may have only some type parameters
|
||||
assert(len(tpars) == len(targs))
|
||||
if len(tpars) == 0 {
|
||||
return typ
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue