whatcanGOwrong

This commit is contained in:
2024-09-19 21:38:24 -04:00
commit d0ae4d841d
17908 changed files with 4096831 additions and 0 deletions
@@ -0,0 +1,32 @@
// Copyright 2024 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 aliases
import (
"go/token"
"go/types"
)
// Package aliases defines backward compatible shims
// for the types.Alias type representation added in 1.22.
// This defines placeholders for x/tools until 1.26.
// NewAlias creates a new TypeName in Package pkg that
// is an alias for the type rhs.
//
// The enabled parameter determines whether the resulting [TypeName]'s
// type is an [types.Alias]. Its value must be the result of a call to
// [Enabled], which computes the effective value of
// GODEBUG=gotypesalias=... by invoking the type checker. The Enabled
// function is expensive and should be called once per task (e.g.
// package import), not once per call to NewAlias.
func NewAlias(enabled bool, pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName {
if enabled {
tname := types.NewTypeName(pos, pkg, name, nil)
newAlias(tname, rhs)
return tname
}
return types.NewTypeName(pos, pkg, name, rhs)
}
@@ -0,0 +1,31 @@
// Copyright 2024 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.
//go:build !go1.22
// +build !go1.22
package aliases
import (
"go/types"
)
// Alias is a placeholder for a go/types.Alias for <=1.21.
// It will never be created by go/types.
type Alias struct{}
func (*Alias) String() string { panic("unreachable") }
func (*Alias) Underlying() types.Type { panic("unreachable") }
func (*Alias) Obj() *types.TypeName { panic("unreachable") }
func Rhs(alias *Alias) types.Type { panic("unreachable") }
// Unalias returns the type t for go <=1.21.
func Unalias(t types.Type) types.Type { return t }
func newAlias(name *types.TypeName, rhs types.Type) *Alias { panic("unreachable") }
// Enabled reports whether [NewAlias] should create [types.Alias] types.
//
// Before go1.22, this function always returns false.
func Enabled() bool { return false }
@@ -0,0 +1,63 @@
// Copyright 2024 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.
//go:build go1.22
// +build go1.22
package aliases
import (
"go/ast"
"go/parser"
"go/token"
"go/types"
)
// Alias is an alias of types.Alias.
type Alias = types.Alias
// Rhs returns the type on the right-hand side of the alias declaration.
func Rhs(alias *Alias) types.Type {
if alias, ok := any(alias).(interface{ Rhs() types.Type }); ok {
return alias.Rhs() // go1.23+
}
// go1.22's Alias didn't have the Rhs method,
// so Unalias is the best we can do.
return Unalias(alias)
}
// Unalias is a wrapper of types.Unalias.
func Unalias(t types.Type) types.Type { return types.Unalias(t) }
// newAlias is an internal alias around types.NewAlias.
// Direct usage is discouraged as the moment.
// Try to use NewAlias instead.
func newAlias(tname *types.TypeName, rhs types.Type) *Alias {
a := types.NewAlias(tname, rhs)
// TODO(go.dev/issue/65455): Remove kludgy workaround to set a.actual as a side-effect.
Unalias(a)
return a
}
// Enabled reports whether [NewAlias] should create [types.Alias] types.
//
// This function is expensive! Call it sparingly.
func Enabled() bool {
// The only reliable way to compute the answer is to invoke go/types.
// We don't parse the GODEBUG environment variable, because
// (a) it's tricky to do so in a manner that is consistent
// with the godebug package; in particular, a simple
// substring check is not good enough. The value is a
// rightmost-wins list of options. But more importantly:
// (b) it is impossible to detect changes to the effective
// setting caused by os.Setenv("GODEBUG"), as happens in
// many tests. Therefore any attempt to cache the result
// is just incorrect.
fset := token.NewFileSet()
f, _ := parser.ParseFile(fset, "a.go", "package p; type A = int", 0)
pkg, _ := new(types.Config).Check("p", fset, []*ast.File{f}, nil)
_, enabled := pkg.Scope().Lookup("A").Type().(*types.Alias)
return enabled
}
@@ -0,0 +1,77 @@
// Copyright 2024 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 aliases_test
import (
"go/ast"
"go/parser"
"go/token"
"go/types"
"testing"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/testenv"
)
// Assert that Obj exists on Alias.
var _ func(*aliases.Alias) *types.TypeName = (*aliases.Alias).Obj
// TestNewAlias tests that alias.NewAlias creates an alias of a type
// whose underlying and Unaliased type is *Named.
// When gotypesalias=1 (or unset) and GoVersion >= 1.22, the type will
// be an *aliases.Alias.
func TestNewAlias(t *testing.T) {
const source = `
package P
type Named int
`
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "hello.go", source, 0)
if err != nil {
t.Fatal(err)
}
var conf types.Config
pkg, err := conf.Check("P", fset, []*ast.File{f}, nil)
if err != nil {
t.Fatal(err)
}
expr := `*Named`
tv, err := types.Eval(fset, pkg, 0, expr)
if err != nil {
t.Fatalf("Eval(%s) failed: %v", expr, err)
}
for _, godebug := range []string{
// "", // The default is in transition; suppress this case for now
"gotypesalias=0",
"gotypesalias=1"} {
t.Run(godebug, func(t *testing.T) {
t.Setenv("GODEBUG", godebug)
enabled := aliases.Enabled()
A := aliases.NewAlias(enabled, token.NoPos, pkg, "A", tv.Type)
if got, want := A.Name(), "A"; got != want {
t.Errorf("Expected A.Name()==%q. got %q", want, got)
}
if got, want := A.Type().Underlying(), tv.Type; got != want {
t.Errorf("Expected A.Type().Underlying()==%q. got %q", want, got)
}
if got, want := aliases.Unalias(A.Type()), tv.Type; got != want {
t.Errorf("Expected Unalias(A)==%q. got %q", want, got)
}
if testenv.Go1Point() >= 22 && godebug != "gotypesalias=0" {
if _, ok := A.Type().(*aliases.Alias); !ok {
t.Errorf("Expected A.Type() to be a types.Alias(). got %q", A.Type())
}
}
})
}
}