mirror of https://github.com/golang/go.git
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:
parent
34f753b9d1
commit
51d599efa2
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
*/
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue