mirror of https://github.com/golang/go.git
go/parser, go/types: allow parenthesized embedded interfaces
This enables the distinction between a method M(int) and an embedded instantiated (parameterized) interface (M(int)). Change-Id: I150d1b1cd53a2b14ddc0ad6336d84078fcb41ad6
This commit is contained in:
parent
9c75653a79
commit
2c0e53f518
|
|
@ -1129,18 +1129,25 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
|
|||
doc := p.leadComment
|
||||
var idents []*ast.Ident
|
||||
var typ ast.Expr
|
||||
x := p.parseTypeName(nil)
|
||||
if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
|
||||
// method
|
||||
idents = []*ast.Ident{ident}
|
||||
scope := ast.NewScope(nil) // method scope
|
||||
tparams, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method")
|
||||
results := p.parseResult(scope, true)
|
||||
typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
|
||||
} else {
|
||||
// embedded interface
|
||||
typ = x
|
||||
p.resolve(typ)
|
||||
switch p.tok {
|
||||
case token.IDENT:
|
||||
x := p.parseTypeName(nil)
|
||||
if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
|
||||
// method
|
||||
idents = []*ast.Ident{ident}
|
||||
scope := ast.NewScope(nil) // method scope
|
||||
tparams, params := p.parseParameters(scope, methodTypeParamsOk|variadicOk, "method")
|
||||
results := p.parseResult(scope, true)
|
||||
typ = &ast.FuncType{Func: token.NoPos, TParams: tparams, Params: params, Results: results}
|
||||
} else {
|
||||
// embedded interface
|
||||
typ = x
|
||||
p.resolve(typ)
|
||||
}
|
||||
case token.LPAREN:
|
||||
// embedded, possibly parameterized interface
|
||||
// (using the enclosing parentheses to distinguish it from a method declaration)
|
||||
typ = p.parseType(true)
|
||||
}
|
||||
p.expectSemi() // call before accessing p.linecomment
|
||||
|
||||
|
|
@ -1163,7 +1170,7 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
|
|||
L:
|
||||
for {
|
||||
switch p.tok {
|
||||
case token.IDENT:
|
||||
case token.IDENT, token.LPAREN:
|
||||
mlist = append(mlist, p.parseMethodSpec(scope))
|
||||
case token.TYPE:
|
||||
p.next()
|
||||
|
|
|
|||
|
|
@ -98,6 +98,11 @@ var valids = []string{
|
|||
// interfaces with (contract) type lists
|
||||
`package p; type _ interface{type int}`,
|
||||
`package p; type _ interface{type int, float32; type bool; m(); type string;}`,
|
||||
|
||||
// interfaces with parenthesized embedded and possibly parameterized interfaces
|
||||
`package p; type I1 interface{}; type I2 interface{ (I1) }`,
|
||||
`package p; type I1(type T) interface{}; type I2 interface{ (I1(int)) }`,
|
||||
`package p; type I1(type T) interface{}; type I2(type T) interface{ (I1(T)) }`,
|
||||
}
|
||||
|
||||
func TestValid(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
This file works as a sort of notebook/implementation log. It replaces my notebook based approach
|
||||
so we have a better track record. I only switched to this file recently, hence it is incomplete.
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
TODO
|
||||
|
||||
- type assertions on/against parameterized types
|
||||
- no need for error messages where a _ type parameter cannot be inferred (_ cannot be used)
|
||||
- use Underlying() to return a type parameter's bound? investigate!
|
||||
|
|
@ -11,16 +13,20 @@ TODO
|
|||
- improve error messages!
|
||||
- use []*TypeParam for tparams in subst? (unclear)
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
OPEN ISSUES
|
||||
|
||||
- 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) ... )
|
||||
- leaving away unused receiver type parameters leads to an error; e.g.: "type S(type T) struct{}; func (S) _()"
|
||||
- allow parenthesized embedded interfaces so we can embed parameterized interfaces and they won't be confused
|
||||
for methods
|
||||
- confirm that it's ok to use inference in missingMethod to compare parameterized methods
|
||||
- now that we allow parenthesized embedded interfaces, should we allow parenthesized embedded fields?
|
||||
(probably yes, for symmetry and consistency).
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
DESIGN/IMPLEMENTATION
|
||||
|
||||
- 11/19/2019: For type parameters with interface bounds to work, the scope of all type parameters in
|
||||
a type parameter list starts at the "type" keyword. This makes all type parameters visible for all
|
||||
type parameter bounds (interfaces that may be parameterized with the type parameters).
|
||||
|
|
@ -67,6 +73,12 @@ DESIGN/IMPLEMENTATION
|
|||
name cannot be a type parameter name declared later (or by the receiver type specification). This
|
||||
seems reasonable and should help avoid confusion which is possible otherwise.
|
||||
|
||||
- 1/6/2020: Embedding a parameterized interface in an interface is not possible because it looks
|
||||
like a method declaration. We probably need to find a away around this; maybe parenthesize the
|
||||
embedded interface (which is currently not permitted, syntactically).
|
||||
- 1/7/2020: We distinguish embedded instantiated (parameterized) interfaces from methods by enclosing
|
||||
the embedded interfaces in parentheses (the design draft recommends this change). Since this opens
|
||||
the possibility for any parenthesized type (that is an interface), we can also allow (parenthesized)
|
||||
interface literals as it is simpler to permit those than forbid them.
|
||||
|
||||
- 1/7/2020: The current implementation permits empty type parameter lists as in: "func f(type)(x int)"
|
||||
but we cannot call such a function as "f()(1)"; the empty type argument list causes problems.
|
||||
We should either disallow empty type parameter lists or document this well.
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ var _ List(byte) = []byte{}
|
|||
|
||||
// A generic binary tree might be declared as follows.
|
||||
type Tree(type E) struct {
|
||||
// TODO(gri) should be able to use Tree w/o repeating type args
|
||||
left, right *Tree(E)
|
||||
payload E
|
||||
}
|
||||
|
|
@ -107,3 +106,43 @@ var _ T // ERROR cannot use generic type T
|
|||
// In type context, parameterized (generic) types cannot use instantiation syntax.
|
||||
// See also NOTES entry from 12/4/2019.
|
||||
var _ (T /* ERROR cannot use generic type T */ )( /* ERROR expected ';' */ int)
|
||||
|
||||
// All types may be parameterized, including interfaces.
|
||||
type I1(type T) interface{
|
||||
m1(T)
|
||||
}
|
||||
|
||||
// To differentiate an instantiated interface such as I1(int) from a method
|
||||
// declaration when embedding it, we must use parentheses around it:
|
||||
type I2 interface {
|
||||
I1(int) // method!
|
||||
(I1(string)) // embedded I1
|
||||
}
|
||||
|
||||
func _() {
|
||||
var x I2
|
||||
x.I1(0)
|
||||
x.m1("foo")
|
||||
}
|
||||
|
||||
// Generally, we now allow any embedded interfaces to be parenthesized.
|
||||
// Because that removes the restriction that embedded interfaces must
|
||||
// be named, we can even "inline" interface literals (though that's of
|
||||
// little practial use - it's simply more complicated to disallow them).
|
||||
// Here are some more examples:
|
||||
type I0 interface {
|
||||
m0()
|
||||
}
|
||||
|
||||
type I3 interface {
|
||||
I0
|
||||
(I1(bool))
|
||||
((interface{ m(string) }))
|
||||
}
|
||||
|
||||
func _() {
|
||||
var x I3
|
||||
x.m0()
|
||||
x.m1(true)
|
||||
x.m("foo")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,12 @@ func (S) m(type B)(B)
|
|||
|
||||
var _ I = S{}
|
||||
|
||||
type E(type T) interface {
|
||||
m(type B)(B)
|
||||
}
|
||||
|
||||
type II interface{
|
||||
m(type C)(C)
|
||||
(E(int))
|
||||
mm() int
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue