mirror of https://github.com/golang/go.git
go/types: more work on checking contract satisfaction
Change-Id: Ibe54e448603c685d714310ff83d4193150d47ebd
This commit is contained in:
parent
b87cfd9558
commit
3c6943daac
|
|
@ -522,7 +522,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
|||
// _before_ calling NewMethodSet: LookupFieldOrMethod completes
|
||||
// any incomplete interfaces so they are available to NewMethodSet
|
||||
// (which assumes that interfaces have been completed already).
|
||||
typ := x.typ
|
||||
typ := unpack(x.typ)
|
||||
if x.mode == variable {
|
||||
// If typ is not an (unnamed) pointer or an interface,
|
||||
// use *typ instead, because the method set of *typ
|
||||
|
|
|
|||
|
|
@ -259,19 +259,31 @@ func (check *Checker) satisfyContract(contr *Contract, targs []Type) bool {
|
|||
|
||||
for i, targ := range targs {
|
||||
iface := contr.ifaceAt(i)
|
||||
if iface == nil {
|
||||
continue // no constraints
|
||||
}
|
||||
// If iface is parameterized, we need to replace the type parameters
|
||||
// with the respective type arguments.
|
||||
if isParameterized(iface) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
// use interface type of type parameter, if any
|
||||
// TODO(gri) is this the correct place for this? (why not in missinMethod?)
|
||||
targ = unpack(targ)
|
||||
// targ must implement iface
|
||||
if m, _ := check.missingMethod(targ, iface, true); m != nil {
|
||||
// check.dump("missing %s (%s, %s)", m, targ, iface)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// unpack returns the interface type of a type parameter,
|
||||
// otherwise it just returns the argument type.
|
||||
// TODO(gri) This function is currently uses if a few places.
|
||||
// Need to determine if there's a better way to handle this.
|
||||
func unpack(typ Type) Type {
|
||||
if tpar, _ := typ.(*TypeParam); tpar != nil {
|
||||
return tpar.Interface()
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,8 +92,7 @@ contract Stringer(T) {
|
|||
|
||||
type List(type T Stringer) struct{
|
||||
data T
|
||||
// TODO(gri) cannot handle this yet
|
||||
//link *List(T)
|
||||
link *List(T)
|
||||
}
|
||||
|
||||
var _ List(MyData)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,23 @@
|
|||
package p
|
||||
|
||||
// Type instantiation must satisfy the contract.
|
||||
type Stringer contract(T) {
|
||||
contract Stringer(T) {
|
||||
T String() string
|
||||
}
|
||||
|
||||
type List(type T Stringer) struct{}
|
||||
type List(type T Stringer) struct{
|
||||
data T
|
||||
link *List(T)
|
||||
}
|
||||
|
||||
var _ List /* ERROR not satisfied */ (int)
|
||||
type MyData string
|
||||
|
||||
func (s MyData) String() string { return string(s) }
|
||||
|
||||
var _ List(MyData)
|
||||
|
||||
func _(type T Stringer)(s []T) (r []string) {
|
||||
for _, x := range s {
|
||||
r = append(r, x.String())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -371,7 +371,8 @@ func (t *Interface) Complete() *Interface {
|
|||
case other == nil:
|
||||
methods = append(methods, m)
|
||||
case explicit:
|
||||
panic("duplicate method " + m.name)
|
||||
// TODO(gri) enable again once contracts code calls Complete with correct interfaces
|
||||
// panic("duplicate method " + m.name)
|
||||
default:
|
||||
// check method signatures after all locally embedded interfaces are computed
|
||||
todo = append(todo, m, other.(*Func))
|
||||
|
|
@ -515,12 +516,16 @@ type Contract struct {
|
|||
|
||||
// ifaceAt returns the interface matching for the respective
|
||||
// contract type parameter with the given index. If c is nil
|
||||
// the result is nil.
|
||||
// the result is the empty interface.
|
||||
func (c *Contract) ifaceAt(index int) *Interface {
|
||||
var iface *Interface
|
||||
if c != nil {
|
||||
return c.IFaces[c.TParams[index]]
|
||||
iface = c.IFaces[c.TParams[index]]
|
||||
}
|
||||
return nil
|
||||
if iface == nil {
|
||||
iface = &emptyInterface
|
||||
}
|
||||
return iface
|
||||
}
|
||||
|
||||
// A TypeParam represents a type parameter type.
|
||||
|
|
@ -539,6 +544,13 @@ func NewTypeParam(obj *TypeName, index int, contr *Contract) *TypeParam {
|
|||
return typ
|
||||
}
|
||||
|
||||
// Interface returns the type parameter's interface as
|
||||
// specified via its contract. If there is no contract,
|
||||
// the result is the empty interface.
|
||||
func (t *TypeParam) Interface() *Interface {
|
||||
return t.contr.ifaceAt(t.index)
|
||||
}
|
||||
|
||||
// Implementations for Type methods.
|
||||
|
||||
func (b *Basic) Underlying() Type { return b }
|
||||
|
|
@ -554,7 +566,7 @@ func (c *Chan) Underlying() Type { return c }
|
|||
func (t *Named) Underlying() Type { return t.underlying }
|
||||
func (p *Parameterized) Underlying() Type { return p.tname.typ.Underlying() }
|
||||
func (c *Contract) Underlying() Type { return c }
|
||||
func (c *TypeParam) Underlying() Type { return c }
|
||||
func (t *TypeParam) Underlying() Type { return t }
|
||||
|
||||
func (b *Basic) String() string { return TypeString(b, nil) }
|
||||
func (a *Array) String() string { return TypeString(a, nil) }
|
||||
|
|
@ -569,4 +581,4 @@ func (c *Chan) String() string { return TypeString(c, nil) }
|
|||
func (t *Named) String() string { return TypeString(t, nil) }
|
||||
func (p *Parameterized) String() string { return TypeString(p, nil) }
|
||||
func (c *Contract) String() string { return TypeString(c, nil) }
|
||||
func (c *TypeParam) String() string { return TypeString(c, nil) }
|
||||
func (t *TypeParam) String() string { return TypeString(t, nil) }
|
||||
|
|
|
|||
Loading…
Reference in New Issue