1
0
mirror of https://github.com/golang/go synced 2024-11-26 04:07:59 -07:00

go/types: expose types.Info.Inferred with -tags=typeparams

Our workaround to get and set types.Info._Inferred makes it harder to
experiment with the new APIs in x/tools.

Instead, just make a copy of the types.Info struct, so that the Inferred
field is accessible when the typeparams build tag is set.

This is a trivially safe change: the only change when not building with
-tags=typeparams is that types.Info._Inferred is removed, and accessing
inferred type information goes through an additional layer of
indirection.

For #46003

Change-Id: I38f2bbb2c80aed28be31d0fe762ccead970476ca
Reviewed-on: https://go-review.googlesource.com/c/go/+/317549
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Rob Findley 2021-05-05 23:03:22 -04:00 committed by Robert Findley
parent 4dbad79510
commit a11a1711b0
6 changed files with 133 additions and 108 deletions

View File

@ -160,101 +160,7 @@ func srcimporter_setUsesCgo(conf *Config) {
conf.go115UsesCgo = true
}
// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
// Types maps expressions to their types, and for constant
// expressions, also their values. Invalid expressions are
// omitted.
//
// For (possibly parenthesized) identifiers denoting built-in
// functions, the recorded signatures are call-site specific:
// if the call result is not a constant, the recorded type is
// an argument-specific signature. Otherwise, the recorded type
// is invalid.
//
// The Types map does not record the type of every identifier,
// only those that appear where an arbitrary expression is
// permitted. For instance, the identifier f in a selector
// expression x.f is found only in the Selections map, the
// identifier z in a variable declaration 'var z int' is found
// only in the Defs map, and identifiers denoting packages in
// qualified identifiers are collected in the Uses map.
Types map[ast.Expr]TypeAndValue
// _Inferred maps calls of parameterized functions that use
// type inference to the _Inferred type arguments and signature
// of the function called. The recorded "call" expression may be
// an *ast.CallExpr (as in f(x)), or an *ast.IndexExpr (s in f[T]).
_Inferred map[ast.Expr]_Inferred
// Defs maps identifiers to the objects they define (including
// package names, dots "." of dot-imports, and blank "_" identifiers).
// For identifiers that do not denote objects (e.g., the package name
// in package clauses, or symbolic variables t in t := x.(type) of
// type switch headers), the corresponding objects are nil.
//
// For an embedded field, Defs returns the field *Var it defines.
//
// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
Defs map[*ast.Ident]Object
// Uses maps identifiers to the objects they denote.
//
// For an embedded field, Uses returns the *TypeName it denotes.
//
// Invariant: Uses[id].Pos() != id.Pos()
Uses map[*ast.Ident]Object
// Implicits maps nodes to their implicitly declared objects, if any.
// The following node and object types may appear:
//
// node declared object
//
// *ast.ImportSpec *PkgName for imports without renames
// *ast.CaseClause type-specific *Var for each type switch case clause (incl. default)
// *ast.Field anonymous parameter *Var (incl. unnamed results)
//
Implicits map[ast.Node]Object
// Selections maps selector expressions (excluding qualified identifiers)
// to their corresponding selections.
Selections map[*ast.SelectorExpr]*Selection
// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
// associated with a specific node but with all files belonging to a package.
// Thus, the package scope can be found in the type-checked Package object.
// Scopes nest, with the Universe scope being the outermost scope, enclosing
// the package scope, which contains (one or more) files scopes, which enclose
// function scopes which in turn enclose statement and function literal scopes.
// Note that even though package-level functions are declared in the package
// scope, the function scopes are embedded in the file scope of the file
// containing the function declaration.
//
// The following node types may appear in Scopes:
//
// *ast.File
// *ast.FuncType
// *ast.BlockStmt
// *ast.IfStmt
// *ast.SwitchStmt
// *ast.TypeSwitchStmt
// *ast.CaseClause
// *ast.CommClause
// *ast.ForStmt
// *ast.RangeStmt
//
Scopes map[ast.Node]*Scope
// InitOrder is the list of package-level initializers in the order in which
// they must be executed. Initializers referring to variables related by an
// initialization dependency appear in topological order, the others appear
// in source order. Variables without an initialization expression do not
// appear in this list.
InitOrder []*Initializer
}
// The Info struct is found in api_notypeparams.go and api_typeparams.go.
// TypeOf returns the type of expression e, or nil if not found.
// Precondition: the Types, Uses and Defs maps are populated.

View File

@ -0,0 +1,104 @@
// 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.
//go:build !typeparams
// +build !typeparams
package types
import "go/ast"
// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
// be incomplete.
type Info struct {
// Types maps expressions to their types, and for constant
// expressions, also their values. Invalid expressions are
// omitted.
//
// For (possibly parenthesized) identifiers denoting built-in
// functions, the recorded signatures are call-site specific:
// if the call result is not a constant, the recorded type is
// an argument-specific signature. Otherwise, the recorded type
// is invalid.
//
// The Types map does not record the type of every identifier,
// only those that appear where an arbitrary expression is
// permitted. For instance, the identifier f in a selector
// expression x.f is found only in the Selections map, the
// identifier z in a variable declaration 'var z int' is found
// only in the Defs map, and identifiers denoting packages in
// qualified identifiers are collected in the Uses map.
Types map[ast.Expr]TypeAndValue
// Defs maps identifiers to the objects they define (including
// package names, dots "." of dot-imports, and blank "_" identifiers).
// For identifiers that do not denote objects (e.g., the package name
// in package clauses, or symbolic variables t in t := x.(type) of
// type switch headers), the corresponding objects are nil.
//
// For an embedded field, Defs returns the field *Var it defines.
//
// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
Defs map[*ast.Ident]Object
// Uses maps identifiers to the objects they denote.
//
// For an embedded field, Uses returns the *TypeName it denotes.
//
// Invariant: Uses[id].Pos() != id.Pos()
Uses map[*ast.Ident]Object
// Implicits maps nodes to their implicitly declared objects, if any.
// The following node and object types may appear:
//
// node declared object
//
// *ast.ImportSpec *PkgName for imports without renames
// *ast.CaseClause type-specific *Var for each type switch case clause (incl. default)
// *ast.Field anonymous parameter *Var (incl. unnamed results)
//
Implicits map[ast.Node]Object
// Selections maps selector expressions (excluding qualified identifiers)
// to their corresponding selections.
Selections map[*ast.SelectorExpr]*Selection
// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
// associated with a specific node but with all files belonging to a package.
// Thus, the package scope can be found in the type-checked Package object.
// Scopes nest, with the Universe scope being the outermost scope, enclosing
// the package scope, which contains (one or more) files scopes, which enclose
// function scopes which in turn enclose statement and function literal scopes.
// Note that even though package-level functions are declared in the package
// scope, the function scopes are embedded in the file scope of the file
// containing the function declaration.
//
// The following node types may appear in Scopes:
//
// *ast.File
// *ast.FuncType
// *ast.BlockStmt
// *ast.IfStmt
// *ast.SwitchStmt
// *ast.TypeSwitchStmt
// *ast.CaseClause
// *ast.CommClause
// *ast.ForStmt
// *ast.RangeStmt
//
Scopes map[ast.Node]*Scope
// InitOrder is the list of package-level initializers in the order in which
// they must be executed. Initializers referring to variables related by an
// initialization dependency appear in topological order, the others appear
// in source order. Variables without an initialization expression do not
// appear in this list.
InitOrder []*Initializer
}
func getInferred(info *Info) map[ast.Expr]_Inferred {
return nil
}

View File

@ -17,14 +17,6 @@ type (
TypeParam = _TypeParam
)
func GetInferred(info *Info) map[ast.Expr]Inferred {
return info._Inferred
}
func SetInferred(info *Info, inferred map[ast.Expr]Inferred) {
info._Inferred = inferred
}
func NewSum(types []Type) Type { return _NewSum(types) }
func (s *Signature) TParams() []*TypeName { return s._TParams() }
@ -37,3 +29,25 @@ func (t *Interface) IsConstraint() bool { return t._IsConstraint() }
func (t *Named) TParams() []*TypeName { return t._TParams() }
func (t *Named) TArgs() []Type { return t._TArgs() }
func (t *Named) SetTArgs(args []Type) { t._SetTArgs(args) }
// Info is documented in api_notypeparams.go.
type Info struct {
Types map[ast.Expr]TypeAndValue
// Inferred maps calls of parameterized functions that use type inference to
// the Inferred type arguments and signature of the function called. The
// recorded "call" expression may be an *ast.CallExpr (as in f(x)), or an
// *ast.IndexExpr (s in f[T]).
Inferred map[ast.Expr]_Inferred
Defs map[*ast.Ident]Object
Uses map[*ast.Ident]Object
Implicits map[ast.Node]Object
Selections map[*ast.SelectorExpr]*Selection
Scopes map[ast.Node]*Scope
InitOrder []*Initializer
}
func getInferred(info *Info) map[ast.Expr]_Inferred {
return info.Inferred
}

View File

@ -88,7 +88,7 @@ func TestInferredInfo(t *testing.T) {
for _, test := range tests {
info := Info{}
SetInferred(&info, make(map[ast.Expr]Inferred))
info.Inferred = make(map[ast.Expr]Inferred)
name, err := mayTypecheck(t, "InferredInfo", test.src, &info)
if err != nil {
t.Errorf("package %s: %v", name, err)
@ -98,7 +98,7 @@ func TestInferredInfo(t *testing.T) {
// look for inferred type arguments and signature
var targs []Type
var sig *Signature
for call, inf := range GetInferred(&info) {
for call, inf := range info.Inferred {
var fun ast.Expr
switch x := call.(type) {
case *ast.CallExpr:

View File

@ -411,7 +411,7 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
func (check *Checker) recordInferred(call ast.Expr, targs []Type, sig *Signature) {
assert(call != nil)
assert(sig != nil)
if m := check._Inferred; m != nil {
if m := getInferred(check.Info); m != nil {
m[call] = _Inferred{targs, sig}
}
}

View File

@ -24,7 +24,8 @@ func sanitizeInfo(info *Info) {
}
}
for e, inf := range info._Inferred {
inferred := getInferred(info)
for e, inf := range inferred {
changed := false
for i, targ := range inf.Targs {
if typ := s.typ(targ); typ != targ {
@ -37,7 +38,7 @@ func sanitizeInfo(info *Info) {
changed = true
}
if changed {
info._Inferred[e] = inf
inferred[e] = inf
}
}