go/types: various minor fixes around interface type bounds

- print type bounds when printing function signatures
- store (named) tyep bound rather than underlying type
- first example using parameterized interface type bound working

Change-Id: Ic7110039d1e09838c8f33040e887e6a4f038d75d
This commit is contained in:
Robert Griesemer 2019-12-03 16:42:32 -08:00
parent 704beb3881
commit edc9611855
7 changed files with 40 additions and 15 deletions

View File

@ -344,7 +344,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
obj Object
index []int
indirect bool
madeCopy bool // for debugging purposes only
)
sel := e.Sel.Name
@ -486,7 +485,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
copy := *m
copy.typ = check.subst(e.Pos(), m.typ, m.tparams, targs)
obj = &copy
madeCopy = true // if we made a copy, the method set verification below can't work
}
}
@ -534,7 +532,14 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
// addressability, should we report the type &(x.typ) instead?
check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
if debug && !madeCopy {
// TODO(gri) The verification pass below is disabled for now because
// method sets don't match method lookup in some cases.
// For instance, if we made a copy above when creating a
// custom method for a parameterized received type, the
// method set method doesn't match (no copy there). There
/// may be other situations.
disabled := true
if !disabled && debug {
// Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
// TODO(gri) This only works because we call LookupFieldOrMethod
// _before_ calling NewMethodSet: LookupFieldOrMethod completes

View File

@ -620,14 +620,14 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
if typ != Typ[Invalid] {
switch b := typ.Underlying().(type) {
case *Interface:
bound = b
bound = typ
case *Contract:
if len(f.Names) != len(b.TParams) {
// TODO(gri) improve error message
check.errorf(f.Type.Pos(), "%d type parameters but contract expects %d", len(f.Names), len(b.TParams))
break // cannot use this contract
}
bound = b
bound = typ
default:
check.errorf(f.Type.Pos(), "%s is not an interface or contract", typ)
}

View File

@ -397,8 +397,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
writeFuncName(buf, obj, qf)
// Func.tparams is used for functions and methods; but for methods
// these are the receiver parameters. Don't print them twice.
// TODO(gri) receiver and type parameters should be in the Func
// object, not the signature. That should simplify things throughout.
// TODO(gri) Consider putting receiver and type parameters in the Func
// object, not the signature. That might simplify things.
if len(obj.tparams) > 0 && (typ == nil || typ.(*Signature).recv == nil) {
buf.WriteString("(type ")
for i, tname := range obj.tparams {
@ -406,6 +406,12 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
buf.WriteString(", ")
}
buf.WriteString(tname.name)
if tname.typ != nil && tname.typ.(*TypeParam).bound != nil {
// TODO(gri) Instead of writing the bound with each type
// parameter, consider bundling them up.
buf.WriteByte(' ')
WriteType(buf, tname.typ.(*TypeParam).bound, nil)
}
}
buf.WriteByte(')')
}

View File

@ -174,12 +174,14 @@ type Adder(type T) interface {
Add(T) T
}
func adderSum(type T Adder)(data []T) T {
func adderSum(type T Adder(T))(data []T) T {
var s T
for _, x := range data {
// TODO(gri) make this work
// s = s.Add(x)
_ = x
s = s.Add(x)
}
return s
}
// TODO(gri) Report an error if we use parameterized interface type bound
// and we forget to pass the type argument.
func buggySig(type T Adder)(data []T) T

View File

@ -11,3 +11,14 @@ contract C(T) {
type Cm(type T C) T
func (a Cm /* ERROR not satisfied */ (T)) m() T
// TODO(gri) make this work
/*
type C interface {
type int
}
type Cm(type T C) T
func (a Cm(T)) m() T
*/

View File

@ -558,7 +558,7 @@ func (check *Checker) NewTypeParam(obj *TypeName, index int, bound Type) *TypePa
// the result is the empty interface.
// TODO(gri) should this be Underlying instead?
func (t *TypeParam) Interface() *Interface {
switch b := t.bound.(type) {
switch b := t.bound.Underlying().(type) {
case nil:
return &emptyInterface
case *Interface:

View File

@ -283,9 +283,10 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
pos := e.Args[i].Pos()
pos = e.Pos() // TODO(gri) remove in favor of more accurate pos on prev. line?
bound := tpar.typ.(*TypeParam).bound // interface or contract or nil
switch b := bound.(type) {
case nil:
// nothing to do (no bound)
if bound == nil {
continue // nothing to do
}
switch b := bound.Underlying().(type) {
case *Interface:
iface := check.subst(token.NoPos, b, tname.tparams, targs).(*Interface)
if !check.satisfyBound(pos, tpar, targs[i], iface) {