forked from TrueCloudLab/neoneo-go
compiler: disallow generic type decl
Need to be reverted and properly handled within the scope of #2376. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
parent
380de580a7
commit
35c3b65c8a
3 changed files with 69 additions and 0 deletions
|
@ -397,6 +397,13 @@ func (c *codegen) analyzeFuncAndGlobalVarUsage() funcUsage {
|
||||||
nodeCache[name] = declPair{n, c.importMap, pkgPath}
|
nodeCache[name] = declPair{n, c.importMap, pkgPath}
|
||||||
return false // will be processed in the next stage
|
return false // will be processed in the next stage
|
||||||
case *ast.GenDecl:
|
case *ast.GenDecl:
|
||||||
|
// Filter out generics usage.
|
||||||
|
err := c.checkGenericsGenDecl(n, pkgPath)
|
||||||
|
if err != nil {
|
||||||
|
c.prog.Err = err
|
||||||
|
return false // Program is invalid.
|
||||||
|
}
|
||||||
|
|
||||||
// After skipping all funcDecls, we are sure that each value spec
|
// After skipping all funcDecls, we are sure that each value spec
|
||||||
// is a globally declared variable or constant. We need to gather global
|
// is a globally declared variable or constant. We need to gather global
|
||||||
// vars from both main and imported packages.
|
// vars from both main and imported packages.
|
||||||
|
@ -575,6 +582,23 @@ func (c *codegen) checkGenericsFuncDecl(n *ast.FuncDecl, funcName string) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkGenericsGenDecl checks whether provided ast.GenDecl has generic code.
|
||||||
|
func (c *codegen) checkGenericsGenDecl(n *ast.GenDecl, pkgPath string) error {
|
||||||
|
// Generic type declaration:
|
||||||
|
// type List[T any] struct
|
||||||
|
// type List[T any] interface
|
||||||
|
if n.Tok == token.TYPE {
|
||||||
|
for _, s := range n.Specs {
|
||||||
|
typeSpec := s.(*ast.TypeSpec)
|
||||||
|
if typeSpec.TypeParams != nil {
|
||||||
|
return fmt.Errorf("%w: type %s is generic", ErrGenericsUnsuppored, c.getIdentName(pkgPath, typeSpec.Name.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// nodeContext contains ast node with the corresponding import map, type info and package information
|
// nodeContext contains ast node with the corresponding import map, type info and package information
|
||||||
// required to retrieve fully qualified node name (if so).
|
// required to retrieve fully qualified node name (if so).
|
||||||
type nodeContext struct {
|
type nodeContext struct {
|
||||||
|
|
|
@ -566,6 +566,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
// x = 2
|
// x = 2
|
||||||
// )
|
// )
|
||||||
case *ast.GenDecl:
|
case *ast.GenDecl:
|
||||||
|
// Filter out generics usage.
|
||||||
|
err := c.checkGenericsGenDecl(n, c.currPkg.PkgPath)
|
||||||
|
if err != nil {
|
||||||
|
c.prog.Err = err
|
||||||
|
return nil // Program is invalid.
|
||||||
|
}
|
||||||
|
|
||||||
if n.Tok == token.VAR || n.Tok == token.CONST {
|
if n.Tok == token.VAR || n.Tok == token.CONST {
|
||||||
c.saveSequencePoint(n)
|
c.saveSequencePoint(n)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,3 +51,41 @@ func TestGenericFuncArgument(t *testing.T) {
|
||||||
_, _, err := compiler.CompileWithOptions("foo.go", strings.NewReader(src), nil)
|
_, _, err := compiler.CompileWithOptions("foo.go", strings.NewReader(src), nil)
|
||||||
require.ErrorIs(t, err, compiler.ErrGenericsUnsuppored)
|
require.ErrorIs(t, err, compiler.ErrGenericsUnsuppored)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenericTypeDecl(t *testing.T) {
|
||||||
|
t.Run("global scope", func(t *testing.T) {
|
||||||
|
src := `
|
||||||
|
package sum
|
||||||
|
type List[T any] struct {
|
||||||
|
next *List[T]
|
||||||
|
val T
|
||||||
|
}
|
||||||
|
|
||||||
|
func Main() any {
|
||||||
|
l := List[int]{}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
`
|
||||||
|
_, _, err := compiler.CompileWithOptions("foo.go", strings.NewReader(src), nil)
|
||||||
|
require.ErrorIs(t, err, compiler.ErrGenericsUnsuppored)
|
||||||
|
})
|
||||||
|
t.Run("local scope", func(t *testing.T) {
|
||||||
|
src := `
|
||||||
|
package sum
|
||||||
|
func Main() any {
|
||||||
|
type (
|
||||||
|
SomeGoodType int
|
||||||
|
|
||||||
|
List[T any] struct {
|
||||||
|
next *List[T]
|
||||||
|
val T
|
||||||
|
}
|
||||||
|
)
|
||||||
|
l := List[int]{}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
`
|
||||||
|
_, _, err := compiler.CompileWithOptions("foo.go", strings.NewReader(src), nil)
|
||||||
|
require.ErrorIs(t, err, compiler.ErrGenericsUnsuppored)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue