mirror of https://github.com/golang/go.git
go/types: always create a bound for each contract parameter
Also: - simplify Contract struct - rename some variables for more consistency Change-Id: Icd10b47ac97d11870c6d4590c154b7efe158c134
This commit is contained in:
parent
24cbbe5229
commit
af12458327
|
|
@ -16,43 +16,37 @@ type contractType struct{}
|
|||
func (contractType) String() string { return "<dummy contract type>" }
|
||||
func (contractType) Underlying() Type { panic("unreachable") }
|
||||
|
||||
func (check *Checker) contractDecl(contr *Contract, e *ast.ContractSpec) {
|
||||
assert(contr.typ == nil)
|
||||
func (check *Checker) contractDecl(obj *Contract, cdecl *ast.ContractSpec) {
|
||||
assert(obj.typ == nil)
|
||||
|
||||
// contracts don't have types, but we need to set a type to
|
||||
// detect recursive declarations and satisfy various assertions
|
||||
contr.typ = new(contractType)
|
||||
obj.typ = new(contractType)
|
||||
|
||||
check.openScope(e, "contract")
|
||||
check.openScope(cdecl, "contract")
|
||||
defer check.closeScope()
|
||||
|
||||
tparams := check.declareTypeParams(nil, e.TParams, nil)
|
||||
tparams := check.declareTypeParams(nil, cdecl.TParams, nil)
|
||||
|
||||
// TODO(gri) review this - we probably don't need lazy allocation anymore
|
||||
// Each type parameter's constraints are represented by a (lazily allocated) named interface.
|
||||
// Given a contract C(P1, P2, ... Pn) { ... } we construct named types C1(P1, P2, ... Pn),
|
||||
// C2(P1, P2, ... Pn), ... Cn(P1, P2, ... Pn) with the respective underlying interfaces
|
||||
// representing the type constraints for each of the type parameters (C1 for P1, C2 for P2, etc.).
|
||||
bounds := make(map[*TypeName]*Named)
|
||||
ifaceFor := func(tpar *TypeName) *Named {
|
||||
named := bounds[tpar]
|
||||
if named == nil {
|
||||
index := tpar.typ.(*TypeParam).index
|
||||
tname := NewTypeName(e.Pos(), check.pkg, contr.name+string(subscript(uint64(index))), nil)
|
||||
named = NewNamed(tname, new(Interface), nil)
|
||||
named.tparams = tparams
|
||||
bounds[tpar] = named
|
||||
}
|
||||
return named
|
||||
// representing the (possibly empty) type constraints for each of the type parameters
|
||||
// (C1 for P1, C2 for P2, etc.).
|
||||
bounds := make([]*Named, len(tparams))
|
||||
for i, tpar := range tparams {
|
||||
tname := NewTypeName(tpar.Pos(), check.pkg, obj.name+string(subscript(uint64(i))), nil)
|
||||
named := NewNamed(tname, new(Interface), nil)
|
||||
named.tparams = tparams
|
||||
bounds[i] = named
|
||||
}
|
||||
|
||||
// collect constraints
|
||||
for _, c := range e.Constraints {
|
||||
for _, c := range cdecl.Constraints {
|
||||
if c.Param != nil {
|
||||
// If a type name is present, it must be one of the contract's type parameters.
|
||||
pos := c.Param.Pos()
|
||||
obj := check.scope.Lookup(c.Param.Name)
|
||||
if obj == nil {
|
||||
tobj := check.scope.Lookup(c.Param.Name)
|
||||
if tobj == nil {
|
||||
check.errorf(pos, "%s not declared by contract", c.Param.Name)
|
||||
continue
|
||||
}
|
||||
|
|
@ -82,8 +76,8 @@ func (check *Checker) contractDecl(contr *Contract, e *ast.ContractSpec) {
|
|||
}
|
||||
}
|
||||
|
||||
tpar := obj.(*TypeName)
|
||||
ifaceName := ifaceFor(tpar)
|
||||
tpar := tobj.(*TypeName)
|
||||
ifaceName := bounds[tpar.typ.(*TypeParam).index]
|
||||
iface := ifaceName.underlying.(*Interface)
|
||||
switch nmethods {
|
||||
case 0:
|
||||
|
|
@ -124,7 +118,7 @@ func (check *Checker) contractDecl(contr *Contract, e *ast.ContractSpec) {
|
|||
// ignore and continue
|
||||
}
|
||||
if len(c.Types) != 1 {
|
||||
check.invalidAST(e.Pos(), "contract contains incorrect (possibly embedded contract) entry")
|
||||
check.invalidAST(cdecl.Pos(), "contract contains incorrect (possibly embedded contract) entry")
|
||||
continue
|
||||
}
|
||||
// TODO(gri) we can probably get away w/o checking this (even if the AST is broken)
|
||||
|
|
@ -141,11 +135,11 @@ func (check *Checker) contractDecl(contr *Contract, e *ast.ContractSpec) {
|
|||
|
||||
// complete interfaces
|
||||
for _, bound := range bounds {
|
||||
check.completeInterface(e.Pos(), bound.underlying.(*Interface))
|
||||
check.completeInterface(cdecl.Pos(), bound.underlying.(*Interface))
|
||||
}
|
||||
|
||||
contr.TParams = tparams
|
||||
contr.Bounds = bounds
|
||||
obj.TParams = tparams
|
||||
obj.Bounds = bounds
|
||||
}
|
||||
|
||||
func (check *Checker) collectTypeConstraints(pos token.Pos, list []Type, types []ast.Expr) []Type {
|
||||
|
|
|
|||
|
|
@ -644,13 +644,8 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
|
|||
targs[i] = tparam.typ
|
||||
}
|
||||
for i, name := range f.Names {
|
||||
bat := obj.boundsAt(i)
|
||||
// TODO(gri) eliminate this nil test by ensuring that all
|
||||
// contract parameters have an associated bound
|
||||
if bat == nil {
|
||||
continue
|
||||
}
|
||||
setBoundAt(index+i, check.instantiate(name.Pos(), bat, targs, nil))
|
||||
bound := obj.boundsAt(i)
|
||||
setBoundAt(index+i, check.instantiate(name.Pos(), bound, targs, nil))
|
||||
}
|
||||
goto next
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,8 +323,8 @@ func (*Func) isDependency() {} // a function may be a dependency of an initializ
|
|||
// A Contract represents a declared contract.
|
||||
type Contract struct {
|
||||
object
|
||||
TParams []*TypeName // type parameters in declaration order
|
||||
Bounds map[*TypeName]*Named // underlying type is always *Interface
|
||||
TParams []*TypeName // type parameters in declaration order
|
||||
Bounds []*Named // underlying type is always *Interface
|
||||
}
|
||||
|
||||
// NewContract returns a new contract.
|
||||
|
|
@ -335,7 +335,7 @@ func NewContract(pos token.Pos, pkg *Package, name string) *Contract {
|
|||
// boundsAt returns the (named) interface for the respective
|
||||
// contract type parameter with the given index.
|
||||
func (c *Contract) boundsAt(index int) *Named {
|
||||
return c.Bounds[c.TParams[index]]
|
||||
return c.Bounds[index]
|
||||
}
|
||||
|
||||
// A Label represents a declared label.
|
||||
|
|
@ -411,12 +411,11 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
|||
WriteType(buf, tpar.typ, qf)
|
||||
}
|
||||
buf.WriteString(") {")
|
||||
i := 0
|
||||
for tpar, bound := range obj.Bounds {
|
||||
for i, bound := range obj.Bounds {
|
||||
if i > 0 {
|
||||
buf.WriteString("; ")
|
||||
}
|
||||
WriteType(buf, tpar.typ, qf)
|
||||
WriteType(buf, obj.TParams[i].typ, qf)
|
||||
buf.WriteByte(' ')
|
||||
WriteType(buf, bound, qf)
|
||||
buf.WriteString(" = ")
|
||||
|
|
|
|||
Loading…
Reference in New Issue