diff --git a/src/go/types/NOTES b/src/go/types/NOTES index 3be20066a1..83241ad5a3 100644 --- a/src/go/types/NOTES +++ b/src/go/types/NOTES @@ -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 diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 3f1b9ab695..349e8ef0d8 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -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++ } } diff --git a/src/go/types/examples/contracts.go2 b/src/go/types/examples/contracts.go2 index b3b0c6ea7a..408c901e65 100644 --- a/src/go/types/examples/contracts.go2 +++ b/src/go/types/examples/contracts.go2 @@ -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 diff --git a/src/go/types/subst.go b/src/go/types/subst.go index e183d7a79a..05e33a256c 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -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 }