go/types: first steps towards contract embedding

Incomplete but all the major steps are outlined now.

Change-Id: I05c0357072d8b2c9f85154d3dd14984d2134de62
This commit is contained in:
Robert Griesemer 2019-12-23 16:36:34 -08:00
parent af12458327
commit b6a8a0a86f
4 changed files with 48 additions and 4 deletions

View File

@ -12,6 +12,7 @@ TODO
- use []*TypeParam for tparams in subst? (unclear)
OPEN ISSUES
- a contract that is used earlier than its declaration may not be set up yet
- instantiating a parameterized function type w/o value or result parameters may have unexpected side-effects
(we don't make a copy of the signature in some cases) - investigate
- using a contract and enumerating type arguments currently leads to an error (e.g. func f(type T C(T)) (x T) ... )

View File

@ -126,10 +126,42 @@ func (check *Checker) contractDecl(obj *Contract, cdecl *ast.ContractSpec) {
if econtr == nil {
check.invalidAST(c.Types[0].Pos(), "invalid embedded contract %s", econtr)
}
etyp := check.typ(c.Types[0])
_ = etyp
// TODO(gri) complete this
check.errorf(c.Types[0].Pos(), "%s: contract embedding not yet implemented", c.Types[0])
// Handle contract lookup so we don't need to set up a special contract mode
// for operands just to carry its information through in form of some contract Type.
// TODO(gri) this code is also in collectTypeParams (decl.go) - factor out!
if ident, ok := unparen(econtr.Fun).(*ast.Ident); ok {
if eobj, _ := check.lookup(ident.Name).(*Contract); eobj != nil {
// TODO(gri) must set up contract if not yet done!
// eobj is a valid contract
// TODO(gri) look for contract cycles!
// contract arguments must match the embedded contract's parameters
if len(econtr.Args) != len(eobj.TParams) {
check.errorf(c.Types[0].Pos(), "%d type parameters but contract expects %d", len(econtr.Args), len(eobj.TParams))
continue
}
// contract arguments must be type parameters
// For now, they must be from the enclosing contract.
// TODO(gri) can we allow any type parameter?
targs := make([]Type, len(econtr.Args))
for i, arg := range econtr.Args {
targ := check.typ(arg)
if parg, _ := targ.(*TypeParam); parg != nil {
// TODO(gri) check that targ is a parameter from the enclosing contract
targs[i] = targ
} else {
check.errorf(arg.Pos(), "%s is not a type parameter", arg)
}
}
// TODO(gri) - implement the steps below
// - for each eobj type parameter, determine its (interface) bound
// - substitute that type parameter with the actual type argument in that interface
// - add the interface as am embedded interface to the bound matching the actual type argument
// - tests! (incl. overlapping methods, etc.)
check.errorf(c.Types[0].Pos(), "%s: contract embedding not yet implemented", c.Types[0])
continue
}
}
check.errorf(c.Types[0].Pos(), "%s is not a contract", c.Types[0])
}
}

View File

@ -636,6 +636,7 @@ func (check *Checker) collectTypeParams(list *ast.FieldList) (tparams []*TypeNam
goto next
}
// obj is a valid contract
// TODO(gri) must set up contract if not yet done!
// Use contract's matching type parameter bound and
// instantiate it with the actual type parameters
// (== targs) present.

View File

@ -3,3 +3,13 @@
// license that can be found in the LICENSE file.
package p
contract C1(a, b, c) {
a a()
b b()
c c()
}
contract C2(a, b) {
C1 /* ERROR contract embedding */ (a, b, a)
}