go/types, types2: implement flexible flag-setting mechanism for tests

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>
This commit is contained in:
Robert Griesemer 2022-03-16 18:19:31 -07:00
parent 6be52abfa1
commit 3395f74d86
18 changed files with 139 additions and 54 deletions

View file

@ -23,8 +23,10 @@
package types2_test
import (
"bytes"
"cmd/compile/internal/syntax"
"flag"
"fmt"
"internal/testenv"
"os"
"path/filepath"
@ -79,18 +81,45 @@ 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.
// 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)
// 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]
}
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, filenames []string, colDelta uint, manual bool) {
@ -98,6 +127,14 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) {
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
@ -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)
@ -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

View file

@ -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"

View file

@ -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 (

View file

@ -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

View file

@ -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

View file

@ -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{}

View file

@ -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"

View file

@ -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

View file

@ -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.
@ -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{}

View file

@ -23,6 +23,7 @@
package types_test
import (
"bytes"
"flag"
"fmt"
"go/ast"
@ -185,18 +186,42 @@ 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) {
@ -204,6 +229,15 @@ func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, man
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")
@ -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)
@ -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") {

View file

@ -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"

View file

@ -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 (

View file

@ -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

View file

@ -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

View file

@ -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{}

View file

@ -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"

View file

@ -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

View file

@ -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.
@ -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 parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}