mirror of https://github.com/golang/go.git
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:
parent
704beb3881
commit
edc9611855
|
|
@ -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 = ©
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(')')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue