go/parser, go/types: steps towards accepting interfaces as type bounds

Also, rebased branch on top of master.

Change-Id: I758b19ae577a4554687b2206c016277c1ca21a45
This commit is contained in:
Robert Griesemer 2019-11-18 16:14:10 -08:00
parent 34f753b9d1
commit 51d599efa2
7 changed files with 35 additions and 14 deletions

View File

@ -474,7 +474,7 @@ type (
type Constraint struct {
Param *Ident // constrained type parameter; or nil (for embedded contracts)
MNames []*Ident // list of method names; or nil (for embedded contracts or type constraints)
Types []Expr // embedded contract (single *CallExpr), list of types, or list of method types (*FuncType)
Types []Expr // embedded contract (single *CallExpr), list of types, or list of method signatures (*FuncType)
}
// Pos and End implementations for expression/type nodes.

View File

@ -1098,21 +1098,22 @@ func (p *parser) parseTypeParams(scope *ast.Scope) *ast.FieldList {
p.expect(token.TYPE)
}
f := new(ast.Field)
if p.tok != token.RBRACK && p.tok != token.RPAREN {
f.Names = p.parseIdentList()
fields := p.parseParameterList(scope, false)
// determine which form we have (list of type parameters with optional
// contract, or type parameters, all with interfaces as type bounds)
for _, f := range fields {
if len(f.Names) == 0 {
assert(f.Type != nil, "expected non-nil type")
f.Names = []*ast.Ident{f.Type.(*ast.Ident)}
f.Type = nil
}
}
if p.tok == token.IDENT {
// contract
f.Type = p.parseTypeName(nil)
}
p.declare(f, nil, scope, ast.Typ, f.Names...)
if lbrack.IsValid() {
rbrack = p.expect(token.RBRACK)
}
return &ast.FieldList{Opening: lbrack, List: []*ast.Field{f}, Closing: rbrack}
return &ast.FieldList{Opening: lbrack, List: fields, Closing: rbrack}
}
func (p *parser) parseParameters(scope *ast.Scope, typeParamsOk, ellipsisOk bool) (tparams, params *ast.FieldList) {

View File

@ -51,7 +51,7 @@ var valids = []string{
`package p; type T (*int)`,
`package p; type T(type P) struct { P }`,
`package p; type T(type P comparable) struct { P }`,
// `package p; type T(type P comparable(P)) struct { P }`,
`package p; type T(type P comparable(P)) struct { P }`,
`package p; type T(type P1, P2) struct { P1; f []P2 }`,
// `package p; type T[type] struct { P }`,
// `package p; type T[type P] struct { P }`,
@ -68,7 +68,7 @@ var valids = []string{
`package p; func _((T(P1, P2, P3)))`,
`package p; func _(type A, B)(a A) B`,
`package p; func _(type A, B C)(a A) B`,
// `package p; func _(type A, B C(A, B))(a A) B`,
`package p; func _(type A, B C(A, B))(a A) B`,
// `package p; type _ struct { T[P] }`,
// `package p; type _ struct { T []E }`,
// `package p; type _ struct { T [P]E }`,
@ -95,6 +95,8 @@ var valids = []string{
`package p; type C contract(T){ T (m(x, int)); }`,
`package p; type C contract(T){ T int; T imported.T; T chan<-int; T m(x int) float64; C0(); imported.C1(int, T,) }`,
`package p; type C contract(T){ T int, imported.T, chan<-int; T m(x int) float64; C0(); imported.C1(int, T,) }`,
`package p; func _(type T1, T2 interface{})(x T1) T2`,
`package p; func _(type T1 interface{ m() }, T2, T3 interface{})(x T1, y T3) T2`,
}
func TestValid(t *testing.T) {

View File

@ -111,6 +111,11 @@ var tests = [][]string{
{"testdata/chans.go2"},
{"testdata/map.go2"},
{"testdata/map2.go2"},
// Go 2 prototype examples
// {"examples/contracts.go2"}, // TODO(gri) enable
{"examples/functions.go2"},
{"examples/types.go2"},
}
var fset = token.NewFileSet()

View File

@ -26,9 +26,8 @@ func (check *Checker) contractType(contr *Contract, e *ast.ContractType) {
tparams[index] = tpar
}
// each type parameter's constraints are represented by an interface
// each type parameter's constraints are represented by a (lazily allocated) interface
ifaces := make(map[*TypeName]*Interface)
ifaceFor := func(tpar *TypeName) *Interface {
iface := ifaces[tpar]
if iface == nil {

View File

@ -47,3 +47,16 @@ func New (type Node, Edge G) (nodes []Node) *Graph(Node, Edge) { panic("unimplem
func (g *Graph(Node, Edge)) ShortestPath(from, to Node) []Edge { panic("unimplemented") }
// Same Graph using interface bounds instead of a contract.
/*
type AltGraph (type Node NodeFace(Edge), Edge EdgeFace(Node)) struct { }
type NodeFace(type Edge) interface {
Edges() []Edge
}
type EdgeFace(type Node) interface {
Nodes() (from, to Node)
}
*/

View File

@ -273,6 +273,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
}
case *ast.CallExpr:
// We may have a parameterized type or an "instantiated" contract.
typ := new(Parameterized)
def.setUnderlying(typ)
if check.parameterizedType(typ, e) {