Skip to content

Commit

Permalink
go/types, types2: implement flexible flag-setting mechanism for tests
Browse files Browse the repository at this point in the history
Use it so set the language version. Adjust relevant tests.

Fixes #49074.

Change-Id: Ida6d0002bdba65b5add6e8728a1700305de18351
Reviewed-on: https://go-review.googlesource.com/c/go/+/393514
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
  • Loading branch information
griesemer authored and pull[bot] committed Mar 28, 2022
1 parent af7deed commit acceded
Show file tree
Hide file tree
Showing 18 changed files with 139 additions and 54 deletions.
65 changes: 47 additions & 18 deletions src/cmd/compile/internal/types2/check_test.go
Expand Up @@ -23,8 +23,10 @@
package types2_test

import (
"bytes"
"cmd/compile/internal/syntax"
"flag"
"fmt"
"internal/testenv"
"os"
"path/filepath"
Expand Down Expand Up @@ -79,25 +81,60 @@ func delta(x, y uint) uint {
}
}

// goVersionRx matches a Go version string using '_', e.g. "go1_12".
var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*_(0|[1-9][0-9]*)$`)
// Note: parseFlags is identical to the version in go/types which is
// why it has a src argument even though here it is always nil.

// parseFlags parses flags from the first line of the given source
// (from src if present, or by reading from the file) if the line
// starts with "//" (line comment) followed by "-" (possiby with
// spaces between). Otherwise the line is ignored.
func parseFlags(filename string, src []byte, flags *flag.FlagSet) error {
// If there is no src, read from the file.
const maxLen = 256
if len(src) == 0 {
f, err := os.Open(filename)
if err != nil {
return err
}

var buf [maxLen]byte
n, err := f.Read(buf[:])
if err != nil {
return err
}
src = buf[:n]
}

// asGoVersion returns a regular Go language version string
// if s is a Go version string using '_' rather than '.' to
// separate the major and minor version numbers (e.g. "go1_12").
// Otherwise it returns the empty string.
func asGoVersion(s string) string {
if goVersionRx.MatchString(s) {
return strings.Replace(s, "_", ".", 1)
// we must have a line comment that starts with a "-"
const prefix = "//"
if !bytes.HasPrefix(src, []byte(prefix)) {
return nil // first line is not a line comment
}
src = src[len(prefix):]
if i := bytes.Index(src, []byte("-")); i < 0 || len(bytes.TrimSpace(src[:i])) != 0 {
return nil // comment doesn't start with a "-"
}
return ""
end := bytes.Index(src, []byte("\n"))
if end < 0 || end > maxLen {
return fmt.Errorf("flags comment line too long")
}

return flags.Parse(strings.Fields(string(src[:end])))
}

func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) {
if len(filenames) == 0 {
t.Fatal("no source files")
}

var conf Config
flags := flag.NewFlagSet("", flag.PanicOnError)
flags.StringVar(&conf.GoVersion, "lang", "", "")
if err := parseFlags(filenames[0], nil, flags); err != nil {
t.Fatal(err)
}

// TODO(gri) remove this or use flag mechanism to set mode if still needed
var mode syntax.Mode
if strings.HasSuffix(filenames[0], ".go2") || manual {
mode |= syntax.AllowGenerics | syntax.AllowMethodTypeParams
Expand All @@ -110,12 +147,6 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) {
pkgName = files[0].PkgName.Value
}

// if no Go version is given, consider the package name
goVersion := *goVersion
if goVersion == "" {
goVersion = asGoVersion(pkgName)
}

listErrors := manual && !*verifyErrors
if listErrors && len(errlist) > 0 {
t.Errorf("--- %s:", pkgName)
Expand All @@ -125,8 +156,6 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) {
}

// typecheck and collect typechecker errors
var conf Config
conf.GoVersion = goVersion
// special case for importC.src
if len(filenames) == 1 && strings.HasSuffix(filenames[0], "importC.src") {
conf.FakeImportC = true
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/compile/internal/types2/testdata/check/decls0.src
@@ -1,10 +1,12 @@
// -lang=go1.17

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// type declarations

package go1_17 // don't permit non-interface elements in interfaces
package p // don't permit non-interface elements in interfaces

import "unsafe"

Expand Down
4 changes: 3 additions & 1 deletion src/cmd/compile/internal/types2/testdata/check/go1_12.src
@@ -1,10 +1,12 @@
// -lang=go1.12

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_12 // go1.12
package p

// numeric literals
const (
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/compile/internal/types2/testdata/check/go1_13.src
@@ -1,10 +1,12 @@
// -lang=go1.13

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_13 // go1.13
package p

// interface embedding

Expand Down
4 changes: 3 additions & 1 deletion src/cmd/compile/internal/types2/testdata/check/go1_16.src
@@ -1,10 +1,12 @@
// -lang=go1.16

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_16 // go1.16
package p

type Slice []byte
type Array [8]byte
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/compile/internal/types2/testdata/check/go1_8.src
@@ -1,10 +1,12 @@
// -lang=go1.8

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_8 // go1.8
package p

// type alias declarations
type any /* ERROR type aliases requires go1.9 or later */ = interface{}
4 changes: 3 additions & 1 deletion src/cmd/compile/internal/types2/testdata/check/issues.src
@@ -1,8 +1,10 @@
// -lang=go1.17

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package go1_17 // don't permit non-interface elements in interfaces
package p // don't permit non-interface elements in interfaces

import (
"fmt"
Expand Down
@@ -1,9 +1,11 @@
// -lang=go1.17

// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The predeclared type comparable is not visible before Go 1.18.

package go1_17
package p

type _ comparable // ERROR undeclared
@@ -1,3 +1,5 @@
// -lang=go1.17

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
Expand All @@ -6,7 +8,7 @@
// needs to report any operations that are not permitted
// before Go 1.18.

package go1_17
package p

type T[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}

Expand Down
64 changes: 44 additions & 20 deletions src/go/types/check_test.go
Expand Up @@ -23,6 +23,7 @@
package types_test

import (
"bytes"
"flag"
"fmt"
"go/ast"
Expand Down Expand Up @@ -185,25 +186,58 @@ func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
}
}

// goVersionRx matches a Go version string using '_', e.g. "go1_12".
var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*_(0|[1-9][0-9]*)$`)
// parseFlags parses flags from the first line of the given source
// (from src if present, or by reading from the file) if the line
// starts with "//" (line comment) followed by "-" (possiby with
// spaces between). Otherwise the line is ignored.
func parseFlags(filename string, src []byte, flags *flag.FlagSet) error {
// If there is no src, read from the file.
const maxLen = 256
if len(src) == 0 {
f, err := os.Open(filename)
if err != nil {
return err
}

// asGoVersion returns a regular Go language version string
// if s is a Go version string using '_' rather than '.' to
// separate the major and minor version numbers (e.g. "go1_12").
// Otherwise it returns the empty string.
func asGoVersion(s string) string {
if goVersionRx.MatchString(s) {
return strings.Replace(s, "_", ".", 1)
var buf [maxLen]byte
n, err := f.Read(buf[:])
if err != nil {
return err
}
src = buf[:n]
}
return ""

// we must have a line comment that starts with a "-"
const prefix = "//"
if !bytes.HasPrefix(src, []byte(prefix)) {
return nil // first line is not a line comment
}
src = src[len(prefix):]
if i := bytes.Index(src, []byte("-")); i < 0 || len(bytes.TrimSpace(src[:i])) != 0 {
return nil // comment doesn't start with a "-"
}
end := bytes.Index(src, []byte("\n"))
if end < 0 || end > maxLen {
return fmt.Errorf("flags comment line too long")
}

return flags.Parse(strings.Fields(string(src[:end])))
}

func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, manual bool, imp Importer) {
if len(filenames) == 0 {
t.Fatal("no source files")
}

var conf Config
conf.Sizes = sizes
flags := flag.NewFlagSet("", flag.PanicOnError)
flags.StringVar(&conf.GoVersion, "lang", "", "")
if err := parseFlags(filenames[0], srcs[0], flags); err != nil {
t.Fatal(err)
}

// TODO(gri) remove this or use flag mechanism to set mode if still needed
if strings.HasSuffix(filenames[0], ".go1") {
// TODO(rfindley): re-enable this test by using GoVersion.
t.Skip("type params are enabled")
Expand All @@ -222,12 +256,6 @@ func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, man
pkgName = files[0].Name.Name
}

// if no Go version is given, consider the package name
goVersion := *goVersion
if goVersion == "" {
goVersion = asGoVersion(pkgName)
}

listErrors := manual && !*verifyErrors
if listErrors && len(errlist) > 0 {
t.Errorf("--- %s:", pkgName)
Expand All @@ -237,10 +265,6 @@ func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, man
}

// typecheck and collect typechecker errors
var conf Config
conf.Sizes = sizes
conf.GoVersion = goVersion

// special case for importC.src
if len(filenames) == 1 {
if strings.HasSuffix(filenames[0], "importC.src") {
Expand Down
4 changes: 3 additions & 1 deletion src/go/types/testdata/check/decls0.src
@@ -1,10 +1,12 @@
// -lang=go1.17

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// type declarations

package go1_17 // don't permit non-interface elements in interfaces
package p // don't permit non-interface elements in interfaces

import "unsafe"

Expand Down
4 changes: 3 additions & 1 deletion src/go/types/testdata/check/go1_12.src
@@ -1,10 +1,12 @@
// -lang=go1.12

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_12 // go1.12
package p

// numeric literals
const (
Expand Down
4 changes: 3 additions & 1 deletion src/go/types/testdata/check/go1_13.src
@@ -1,10 +1,12 @@
// -lang=go1.13

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_13 // go1.13
package p

// interface embedding

Expand Down
4 changes: 3 additions & 1 deletion src/go/types/testdata/check/go1_16.src
@@ -1,10 +1,12 @@
// -lang=go1.16

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_16 // go1.16
package p

type Slice []byte
type Array [8]byte
Expand Down
4 changes: 3 additions & 1 deletion src/go/types/testdata/check/go1_8.src
@@ -1,10 +1,12 @@
// -lang=go1.8

// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Check Go language version-specific errors.

package go1_8 // go1.8
package p

// type alias declarations
type any = /* ERROR type aliases requires go1.9 or later */ interface{}
Expand Down
4 changes: 3 additions & 1 deletion src/go/types/testdata/check/issues.src
@@ -1,8 +1,10 @@
// -lang=go1.17

// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package go1_17 // don't permit non-interface elements in interfaces
package p // don't permit non-interface elements in interfaces

import (
"fmt"
Expand Down

0 comments on commit acceded

Please sign in to comment.