go/types: more work on checking contract satisfaction

Change-Id: Ibe54e448603c685d714310ff83d4193150d47ebd
This commit is contained in:
Robert Griesemer 2019-08-12 14:13:31 -07:00
parent b87cfd9558
commit 3c6943daac
5 changed files with 52 additions and 16 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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) }