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>
package types2_test
import (
+ "bytes"
"cmd/compile/internal/syntax"
"flag"
+ "fmt"
"internal/testenv"
"os"
"path/filepath"
}
}
-// 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) {
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
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)
}
// 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
+// -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"
+// -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 (
+// -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
+// -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
+// -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{}
+// -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"
+// -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
+// -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.
// 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{}
package types_test
import (
+ "bytes"
"flag"
"fmt"
"go/ast"
}
}
-// 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) {
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")
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)
}
// 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") {
+// -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"
+// -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 (
+// -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
+// -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
+// -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{}
+// -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"
+// -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
+// -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.
// 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{}