x/tools: add explicit Unalias operations

This change is the result of an audit of all type assertions
and type switches whose operand is a types.Type. (These were
enumerated with an analyzer tool.)

If the operand is already the result of a call to Underlying
or Unalias, there is nothing to do, but in other cases,
explicit Unalias operations were added in order to preserve
the existing behavior when go/types starts creating explicit
Alias types.

This change does not address any desired behavior changes
required for the ideal handling of aliases; they will wait
for a followup. In a number of places I have added comments
matching "TODO.*alias".

It may be prudent to split this change by top-level directory,
both for ease of review, and of later bisection if needed.

During the audit, there appeared to be a recurring need
for the following operators:
- (*types.Func).Signature (golang/go#65772);
- Deref(Type): it's easy to forget to strip off the
  Alias constructor;
- ReceiverName (CL 565075), for destructuring receiver
  types such as T and *T, in which up to two Aliases
  might be present.

Updates golang/go#65294

Change-Id: I5180b9bae1c9191807026b8e0dc6f15ed4953b9a
Reviewed-on: https://go-review.googlesource.com/c/tools/+/565035
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Auto-Submit: Alan Donovan <adonovan@google.com>
This commit is contained in:
Alan Donovan 2024-02-14 14:15:22 -05:00 коммит произвёл Gopher Robot
Родитель a6c03c86fe
Коммит 38b0e9bfdb
53 изменённых файлов: 221 добавлений и 121 удалений

Просмотреть файл

@ -12,6 +12,8 @@ import (
"go/types"
"io"
"math/big"
"golang.org/x/tools/internal/aliases"
)
// TODO(gri) use tabwriter for alignment?
@ -56,7 +58,7 @@ func (p *printer) printf(format string, args ...interface{}) {
// denoted by obj is not an interface and has methods. Otherwise it returns
// the zero value.
func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
named, _ := obj.Type().(*types.Named)
named, _ := aliases.Unalias(obj.Type()).(*types.Named)
if named == nil {
// A type name's type can also be the
// exported basic type unsafe.Pointer.

Просмотреть файл

@ -12,7 +12,11 @@
package main
import "go/types"
import (
"go/types"
"golang.org/x/tools/internal/aliases"
)
func (p *printer) writeType(this *types.Package, typ types.Type) {
p.writeTypeInternal(this, typ, make([]types.Type, 8))
@ -173,6 +177,10 @@ func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited
p.print(")")
}
case *aliases.Alias:
// TODO(adonovan): display something aliasy.
p.writeTypeInternal(this, aliases.Unalias(t), visited)
case *types.Named:
s := "<Named w/o object>"
if obj := t.Obj(); obj != nil {

Просмотреть файл

@ -19,6 +19,7 @@ import (
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typesinternal"
)
@ -358,7 +359,7 @@ func appendNames(names []*types.Named, typ types.Type) []*types.Named {
Elem() types.Type
}
switch t := typ.(type) {
switch t := aliases.Unalias(typ).(type) {
case *types.Named:
names = append(names, t)
case *types.Map:
@ -469,7 +470,7 @@ func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error)
description = "alias of "
} else if obj.Pos() == n.Pos() {
description = "definition of " // (Named type)
} else if _, ok := typ.(*types.Basic); ok {
} else if _, ok := aliases.Unalias(typ).(*types.Basic); ok {
description = "reference to built-in "
} else {
description = "reference to " // (Named type)
@ -486,7 +487,7 @@ func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error)
description = description + "type " + qpos.typeString(typ)
// Show sizes for structs and named types (it's fairly obvious for others).
switch typ.(type) {
switch aliases.Unalias(typ).(type) {
case *types.Named, *types.Struct:
szs := types.StdSizes{WordSize: 8, MaxAlign: 8} // assume amd64
description = fmt.Sprintf("%s (size %d, align %d)", description,
@ -576,7 +577,7 @@ func (r *describeTypeResult) PrintPlain(printf printfFunc) {
printf(r.node, "%s", r.description)
// Show the underlying type for a reference to a named type.
if nt, ok := r.typ.(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
if nt, ok := aliases.Unalias(r.typ).(*types.Named); ok && r.node.Pos() != nt.Obj().Pos() {
// TODO(adonovan): improve display of complex struct/interface types.
printf(nt.Obj(), "defined as %s", r.qpos.typeString(nt.Underlying()))
}
@ -585,7 +586,7 @@ func (r *describeTypeResult) PrintPlain(printf printfFunc) {
if len(r.methods) == 0 {
// Only report null result for type kinds
// capable of bearing methods.
switch r.typ.(type) {
switch aliases.Unalias(r.typ).(type) {
case *types.Interface, *types.Struct, *types.Named:
printf(r.node, "No methods.")
}
@ -596,7 +597,7 @@ func (r *describeTypeResult) PrintPlain(printf printfFunc) {
func (r *describeTypeResult) JSON(fset *token.FileSet) []byte {
var namePos, nameDef string
if nt, ok := r.typ.(*types.Named); ok {
if nt, ok := aliases.Unalias(r.typ).(*types.Named); ok {
namePos = fset.Position(nt.Obj().Pos()).String()
nameDef = nt.Underlying().String()
}
@ -727,7 +728,7 @@ func formatMember(obj types.Object, maxname int) string {
}
var typestr string
// Abbreviate long aggregate type names.
switch typ := typ.(type) {
switch typ := aliases.Unalias(typ).(type) {
case *types.Interface:
if typ.NumMethods() > 1 {
typestr = "interface{...}"

Просмотреть файл

@ -16,6 +16,7 @@ import (
"golang.org/x/tools/cmd/guru/serial"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/refactor/importgraph"
)
@ -157,7 +158,7 @@ func implements(q *Query) error {
}
var pos interface{} = qpos
if nt, ok := deref(T).(*types.Named); ok {
if nt, ok := aliases.Unalias(deref(T)).(*types.Named); ok {
pos = nt.Obj()
}
@ -230,7 +231,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
for i, sub := range r.to {
if !isInterface(sub) {
if r.method == nil {
printf(deref(sub).(*types.Named).Obj(), "\t%s %s type %s",
printf(aliases.Unalias(deref(sub)).(*types.Named).Obj(), "\t%s %s type %s",
relation, typeKind(sub), r.qpos.typeString(sub))
} else {
meth(r.toMethod[i])
@ -240,7 +241,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
for i, sub := range r.to {
if isInterface(sub) {
if r.method == nil {
printf(sub.(*types.Named).Obj(), "\t%s %s type %s",
printf(aliases.Unalias(sub).(*types.Named).Obj(), "\t%s %s type %s",
relation, typeKind(sub), r.qpos.typeString(sub))
} else {
meth(r.toMethod[i])
@ -251,7 +252,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
relation = "implements"
for i, super := range r.from {
if r.method == nil {
printf(super.(*types.Named).Obj(), "\t%s %s",
printf(aliases.Unalias(super).(*types.Named).Obj(), "\t%s %s",
relation, r.qpos.typeString(super))
} else {
meth(r.fromMethod[i])
@ -270,7 +271,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
}
for i, super := range r.from {
if r.method == nil {
printf(super.(*types.Named).Obj(), "\t%s %s",
printf(aliases.Unalias(super).(*types.Named).Obj(), "\t%s %s",
relation, r.qpos.typeString(super))
} else {
meth(r.fromMethod[i])
@ -288,7 +289,7 @@ func (r *implementsResult) PrintPlain(printf printfFunc) {
for i, psuper := range r.fromPtr {
if r.method == nil {
printf(psuper.(*types.Named).Obj(), "\t%s %s",
printf(aliases.Unalias(psuper).(*types.Named).Obj(), "\t%s %s",
relation, r.qpos.typeString(psuper))
} else {
meth(r.fromPtrMethod[i])
@ -332,7 +333,7 @@ func makeImplementsTypes(tt []types.Type, fset *token.FileSet) []serial.Implemen
func makeImplementsType(T types.Type, fset *token.FileSet) serial.ImplementsType {
var pos token.Pos
if nt, ok := deref(T).(*types.Named); ok { // implementsResult.t may be non-named
if nt, ok := aliases.Unalias(deref(T)).(*types.Named); ok { // implementsResult.t may be non-named
pos = nt.Obj().Pos()
}
return serial.ImplementsType{

Просмотреть файл

@ -15,6 +15,7 @@ import (
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -71,7 +72,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
return
}
var structuralTypes []types.Type
switch typ := typ.(type) {
switch typ := aliases.Unalias(typ).(type) {
case *types.TypeParam:
terms, err := typeparams.StructuralTerms(typ)
if err != nil {
@ -84,7 +85,8 @@ func run(pass *analysis.Pass) (interface{}, error) {
structuralTypes = append(structuralTypes, typ)
}
for _, typ := range structuralTypes {
under := deref(typ.Underlying())
// TODO(adonovan): this operation is questionable.
under := aliases.Unalias(deref(typ.Underlying()))
strct, ok := under.(*types.Struct)
if !ok {
// skip non-struct composite literals
@ -142,9 +144,11 @@ func run(pass *analysis.Pass) (interface{}, error) {
return nil, nil
}
// Note: this is not the usual deref operator!
// It strips off all Pointer constructors (and their Aliases).
func deref(typ types.Type) types.Type {
for {
ptr, ok := typ.(*types.Pointer)
ptr, ok := aliases.Unalias(typ).(*types.Pointer)
if !ok {
break
}
@ -153,18 +157,18 @@ func deref(typ types.Type) types.Type {
return typ
}
// isLocalType reports whether typ belongs to the same package as pass.
// TODO(adonovan): local means "internal to a function"; rename to isSamePackageType.
func isLocalType(pass *analysis.Pass, typ types.Type) bool {
switch x := typ.(type) {
switch x := aliases.Unalias(typ).(type) {
case *types.Struct:
// struct literals are local types
return true
case *types.Pointer:
return isLocalType(pass, x.Elem())
case *types.Named:
case interface{ Obj() *types.TypeName }: // *Named or *TypeParam (aliases were removed already)
// names in package foo are local to foo_test too
return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
case *types.TypeParam:
return strings.TrimSuffix(x.Obj().Pkg().Path(), "_test") == strings.TrimSuffix(pass.Pkg.Path(), "_test")
}
return false
}

Просмотреть файл

@ -18,6 +18,7 @@ import (
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -255,7 +256,7 @@ func lockPath(tpkg *types.Package, typ types.Type, seen map[types.Type]bool) typ
}
seen[typ] = true
if tpar, ok := typ.(*types.TypeParam); ok {
if tpar, ok := aliases.Unalias(typ).(*types.TypeParam); ok {
terms, err := typeparams.StructuralTerms(tpar)
if err != nil {
return nil // invalid type

Просмотреть файл

@ -102,8 +102,7 @@ func containsError(typ types.Type) bool {
return true
}
}
case *types.Named,
*aliases.Alias:
case *types.Named, *aliases.Alias:
return check(t.Underlying())
// We list the remaining valid type kinds for completeness.

Просмотреть файл

@ -14,6 +14,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typesinternal"
)
@ -136,7 +137,7 @@ func isHTTPFuncOrMethodOnClient(info *types.Info, expr *ast.CallExpr) bool {
if analysisutil.IsNamedType(typ, "net/http", "Client") {
return true // method on http.Client.
}
ptr, ok := typ.(*types.Pointer)
ptr, ok := aliases.Unalias(typ).(*types.Pointer)
return ok && analysisutil.IsNamedType(ptr.Elem(), "net/http", "Client") // method on *http.Client.
}

Просмотреть файл

@ -7,6 +7,7 @@ package ifaceassert
import (
"go/types"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -94,6 +95,10 @@ func (w *tpWalker) isParameterized(typ types.Type) (res bool) {
case *types.Chan:
return w.isParameterized(t.Elem())
case *aliases.Alias:
// TODO(adonovan): think about generic aliases.
return w.isParameterized(aliases.Unalias(t))
case *types.Named:
list := t.TypeArgs()
for i, n := 0, list.Len(); i < n; i++ {

Просмотреть файл

@ -14,6 +14,7 @@ import (
"go/types"
"os"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/analysisinternal"
)
@ -115,7 +116,7 @@ func Imports(pkg *types.Package, path string) bool {
// This function avoids allocating the concatenation of "pkg.Name",
// which is important for the performance of syntax matching.
func IsNamedType(t types.Type, pkgPath string, names ...string) bool {
n, ok := t.(*types.Named)
n, ok := aliases.Unalias(t).(*types.Named)
if !ok {
return false
}

Просмотреть файл

@ -24,6 +24,7 @@ import (
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -959,6 +960,8 @@ func isStringer(sig *types.Signature) bool {
// It is almost always a mistake to print a function value.
func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
if typ := pass.TypesInfo.Types[e].Type; typ != nil {
// Don't call Underlying: a named func type with a String method is ok.
// TODO(adonovan): it would be more precise to check isStringer.
_, ok := typ.(*types.Signature)
return ok
}
@ -1010,7 +1013,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
// Skip checking functions with unknown type.
return
}
if sig, ok := typ.(*types.Signature); ok {
if sig, ok := typ.Underlying().(*types.Signature); ok {
if !sig.Variadic() {
// Skip checking non-variadic functions.
return
@ -1020,7 +1023,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
typ := params.At(firstArg).Type()
typ = typ.(*types.Slice).Elem()
it, ok := typ.(*types.Interface)
it, ok := aliases.Unalias(typ).(*types.Interface)
if !ok || !it.Empty() {
// Skip variadic functions accepting non-interface{} args.
return

Просмотреть файл

@ -10,6 +10,7 @@ import (
"go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -72,7 +73,7 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
return true
}
if typ, _ := typ.(*types.TypeParam); typ != nil {
if typ, _ := aliases.Unalias(typ).(*types.TypeParam); typ != nil {
// Avoid infinite recursion through type parameters.
if m.seen[typ] {
return true
@ -275,7 +276,7 @@ func (m *argMatcher) match(typ types.Type, topLevel bool) bool {
}
func isConvertibleToString(typ types.Type) bool {
if bt, ok := typ.(*types.Basic); ok && bt.Kind() == types.UntypedNil {
if bt, ok := aliases.Unalias(typ).(*types.Basic); ok && bt.Kind() == types.UntypedNil {
// We explicitly don't want untyped nil, which is
// convertible to both of the interfaces below, as it
// would just panic anyway.

Просмотреть файл

@ -21,6 +21,7 @@ import (
"golang.org/x/tools/go/analysis/passes/inspect"
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -99,7 +100,7 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) {
return
}
var structuralTypes []types.Type
switch t := t.(type) {
switch t := aliases.Unalias(t).(type) {
case *types.TypeParam:
terms, err := typeparams.StructuralTerms(t)
if err != nil {

Просмотреть файл

@ -60,10 +60,12 @@ func describe(typ, inType types.Type, inName string) string {
}
func typeName(typ types.Type) string {
if v, _ := typ.(interface{ Name() string }); v != nil {
typ = aliases.Unalias(typ)
// TODO(adonovan): don't discard alias type, return its name.
if v, _ := typ.(*types.Basic); v != nil {
return v.Name()
}
if v, _ := typ.(interface{ Obj() *types.TypeName }); v != nil {
if v, _ := typ.(interface{ Obj() *types.TypeName }); v != nil { // Named, TypeParam
return v.Obj().Name()
}
return ""

Просмотреть файл

@ -17,6 +17,7 @@ import (
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
)
//go:embed doc.go
@ -270,7 +271,7 @@ func forbiddenMethod(info *types.Info, call *ast.CallExpr) (*types.Var, *types.S
func formatMethod(sel *types.Selection, fn *types.Func) string {
var ptr string
rtype := sel.Recv()
if p, ok := rtype.(*types.Pointer); ok {
if p, ok := aliases.Unalias(rtype).(*types.Pointer); ok {
ptr = "*"
rtype = p.Elem()
}

Просмотреть файл

@ -252,6 +252,8 @@ func validateFuzzArgs(pass *analysis.Pass, params *types.Tuple, expr ast.Expr) b
}
func isTestingType(typ types.Type, testingType string) bool {
// No Unalias here: I doubt "go test" recognizes
// "type A = *testing.T; func Test(A) {}" as a test.
ptr, ok := typ.(*types.Pointer)
if !ok {
return false

Просмотреть файл

@ -107,7 +107,7 @@ func badFormatAt(info *types.Info, e ast.Expr) int {
return -1
}
t, ok := tv.Type.(*types.Basic)
t, ok := tv.Type.(*types.Basic) // sic, no unalias
if !ok || t.Info()&types.IsString == 0 {
return -1
}

Просмотреть файл

@ -17,6 +17,7 @@ import (
"golang.org/x/tools/go/analysis/passes/internal/analysisutil"
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/aliases"
)
//go:embed doc.go
@ -88,7 +89,7 @@ func isSafeUintptr(info *types.Info, x ast.Expr) bool {
// by the time we get to the conversion at the end.
// For now approximate by saying that *Header is okay
// but Header is not.
pt, ok := info.Types[x.X].Type.(*types.Pointer)
pt, ok := aliases.Unalias(info.Types[x.X].Type).(*types.Pointer)
if ok && isReflectHeader(pt.Elem()) {
return true
}

Просмотреть файл

@ -125,10 +125,7 @@ func isDeadStore(store *ssa.Store, obj ssa.Value, addr ssa.Instruction) bool {
// isStructOrArray returns whether the underlying type is struct or array.
func isStructOrArray(tp types.Type) bool {
if named, ok := tp.(*types.Named); ok {
tp = named.Underlying()
}
switch tp.(type) {
switch tp.Underlying().(type) {
case *types.Array:
return true
case *types.Struct:
@ -146,7 +143,7 @@ func hasStructOrArrayType(v ssa.Value) bool {
// func (t T) f() { ...}
// the receiver object is of type *T:
// t0 = local T (t) *T
if tp, ok := alloc.Type().(*types.Pointer); ok {
if tp, ok := aliases.Unalias(alloc.Type()).(*types.Pointer); ok {
return isStructOrArray(tp.Elem())
}
return false
@ -162,14 +159,12 @@ func hasStructOrArrayType(v ssa.Value) bool {
func getFieldName(tp types.Type, index int) string {
// TODO(adonovan): use
// stp, ok := typeparams.Deref(tp).Underlying().(*types.Struct); ok {
// when Deref is defined.
// when Deref is defined. But see CL 565456 for a better fix.
if pt, ok := aliases.Unalias(tp).(*types.Pointer); ok {
tp = pt.Elem()
}
if named, ok := aliases.Unalias(tp).(*types.Named); ok {
tp = named.Underlying()
}
if stp, ok := tp.(*types.Struct); ok {
if stp, ok := tp.Underlying().(*types.Struct); ok {
return stp.Field(index).Name()
}
return fmt.Sprintf("%d", index)

Просмотреть файл

@ -375,7 +375,7 @@ func (r *rta) interfaces(C types.Type) []*types.Interface {
// and update the 'implements' relation.
r.interfaceTypes.Iterate(func(I types.Type, v interface{}) {
iinfo := v.(*interfaceTypeInfo)
if I := I.(*types.Interface); implements(cinfo, iinfo) {
if I := aliases.Unalias(I).(*types.Interface); implements(cinfo, iinfo) {
iinfo.implementations = append(iinfo.implementations, C)
cinfo.implements = append(cinfo.implements, I)
}
@ -457,7 +457,7 @@ func (r *rta) addRuntimeType(T types.Type, skip bool) {
// Each package maintains its own set of types it has visited.
var n *types.Named
switch T := T.(type) {
switch T := aliases.Unalias(T).(type) {
case *types.Named:
n = T
case *types.Pointer:

Просмотреть файл

@ -12,6 +12,7 @@ import (
"golang.org/x/tools/go/callgraph"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -410,7 +411,7 @@ func (b *builder) tassert(a *ssa.TypeAssert) {
// The case where a is <a.AssertedType, bool> register so there
// is a flow from a.X to a[0]. Here, a[0] is represented as an
// indexedLocal: an entry into local tuple register a at index 0.
tup := a.Type().Underlying().(*types.Tuple)
tup := a.Type().(*types.Tuple)
t := tup.At(0).Type()
local := indexedLocal{val: a, typ: t, index: 0}
@ -421,7 +422,7 @@ func (b *builder) tassert(a *ssa.TypeAssert) {
// and t1 where the source is indexed local representing a value
// from tuple register t2 at index i and the target is t1.
func (b *builder) extract(e *ssa.Extract) {
tup := e.Tuple.Type().Underlying().(*types.Tuple)
tup := e.Tuple.Type().(*types.Tuple)
t := tup.At(e.Index).Type()
local := indexedLocal{val: e.Tuple, typ: t, index: e.Index}
@ -527,7 +528,7 @@ func (b *builder) next(n *ssa.Next) {
if n.IsString {
return
}
tup := n.Type().Underlying().(*types.Tuple)
tup := n.Type().(*types.Tuple)
kt := tup.At(1).Type()
vt := tup.At(2).Type()
@ -657,7 +658,7 @@ func addReturnFlows(b *builder, r *ssa.Return, site ssa.Value) {
return
}
tup := site.Type().Underlying().(*types.Tuple)
tup := site.Type().(*types.Tuple)
for i, r := range results {
local := indexedLocal{val: site, typ: tup.At(i).Type(), index: i}
b.addInFlowEdge(b.nodeFromVal(r), local)
@ -671,7 +672,7 @@ func (b *builder) multiconvert(c *ssa.MultiConvert) {
// This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on.
var terms []*types.Term
var err error
switch typ := typ.(type) {
switch typ := aliases.Unalias(typ).(type) {
case *types.TypeParam:
terms, err = typeparams.StructuralTerms(typ)
case *types.Union:
@ -692,7 +693,7 @@ func (b *builder) multiconvert(c *ssa.MultiConvert) {
}
// isValuePreserving returns true if a conversion from ut_src to
// ut_dst is value-preserving, i.e. just a change of type.
// Precondition: neither argument is a named type.
// Precondition: neither argument is a named or alias type.
isValuePreserving := func(ut_src, ut_dst types.Type) bool {
// Identical underlying types?
if types.IdenticalIgnoreTags(ut_dst, ut_src) {
@ -740,7 +741,7 @@ func (b *builder) addInFlowEdge(s, d node) {
// Creates const, pointer, global, func, and local nodes based on register instructions.
func (b *builder) nodeFromVal(val ssa.Value) node {
if p, ok := val.Type().(*types.Pointer); ok && !types.IsInterface(p.Elem()) && !isFunction(p.Elem()) {
if p, ok := aliases.Unalias(val.Type()).(*types.Pointer); ok && !types.IsInterface(p.Elem()) && !isFunction(p.Elem()) {
// Nested pointer to interfaces are modeled as a special
// nestedPtrInterface node.
if i := interfaceUnderPtr(p.Elem()); i != nil {

Просмотреть файл

@ -15,6 +15,7 @@ import (
"golang.org/x/tools/go/callgraph/cha"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
"golang.org/x/tools/internal/aliases"
)
func TestNodeInterface(t *testing.T) {
@ -35,7 +36,7 @@ func TestNodeInterface(t *testing.T) {
reg := firstRegInstr(main) // t0 := *gl
X := pkg.Type("X").Type()
gl := pkg.Var("gl")
glPtrType, ok := gl.Type().(*types.Pointer)
glPtrType, ok := aliases.Unalias(gl.Type()).(*types.Pointer)
if !ok {
t.Fatalf("could not cast gl variable to pointer type")
}

Просмотреть файл

@ -9,6 +9,7 @@ import (
"golang.org/x/tools/go/callgraph"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -24,7 +25,7 @@ func isReferenceNode(n node) bool {
return true
}
if _, ok := n.Type().(*types.Pointer); ok {
if _, ok := aliases.Unalias(n.Type()).(*types.Pointer); ok {
return true
}
@ -166,6 +167,7 @@ func siteCallees(c ssa.CallInstruction, callgraph *callgraph.Graph) []*ssa.Funct
}
func canHaveMethods(t types.Type) bool {
t = aliases.Unalias(t)
if _, ok := t.(*types.Named); ok {
return true
}

Просмотреть файл

@ -20,6 +20,8 @@ import (
"strings"
"text/scanner"
"unicode/utf8"
"golang.org/x/tools/internal/aliases"
)
type parser struct {
@ -241,7 +243,7 @@ func (p *parser) parseName() string {
}
func deref(typ types.Type) types.Type {
if p, _ := typ.(*types.Pointer); p != nil {
if p, _ := aliases.Unalias(typ).(*types.Pointer); p != nil {
typ = p.Elem()
}
return typ
@ -260,7 +262,7 @@ func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) {
if aname, ok := p.aliases[n]; ok {
name = aname
} else {
switch typ := deref(typ).(type) {
switch typ := aliases.Unalias(deref(typ)).(type) {
case *types.Basic:
name = typ.Name()
case *types.Named:
@ -579,7 +581,7 @@ func (p *parser) parseNamedType(nlist []interface{}) types.Type {
t := obj.Type()
p.update(t, nlist)
nt, ok := t.(*types.Named)
nt, ok := aliases.Unalias(t).(*types.Named)
if !ok {
// This can happen for unsafe.Pointer, which is a TypeName holding a Basic type.
pt := p.parseType(pkg)
@ -1334,7 +1336,7 @@ func (p *parser) parsePackage() *types.Package {
}
p.fixups = nil
for _, typ := range p.typeList {
if it, ok := typ.(*types.Interface); ok {
if it, ok := aliases.Unalias(typ).(*types.Interface); ok {
it.Complete()
}
}

Просмотреть файл

@ -81,16 +81,15 @@ import (
"os"
"sync"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/versions"
)
type opaqueType struct {
types.Type
name string
}
type opaqueType struct{ name string }
func (t *opaqueType) String() string { return t.name }
func (t *opaqueType) String() string { return t.name }
func (t *opaqueType) Underlying() types.Type { return t }
var (
varOk = newVar("ok", tBool)
@ -103,7 +102,7 @@ var (
tInvalid = types.Typ[types.Invalid]
tString = types.Typ[types.String]
tUntypedNil = types.Typ[types.UntypedNil]
tRangeIter = &opaqueType{nil, "iter"} // the type of all "range" iterators
tRangeIter = &opaqueType{"iter"} // the type of all "range" iterators
tEface = types.NewInterfaceType(nil, nil).Complete()
// SSA Value constants.
@ -802,7 +801,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
if types.IsInterface(rt) {
// If v may be an interface type I (after instantiating),
// we must emit a check that v is non-nil.
if recv, ok := sel.recv.(*types.TypeParam); ok {
if recv, ok := aliases.Unalias(sel.recv).(*types.TypeParam); ok {
// Emit a nil check if any possible instantiation of the
// type parameter is an interface type.
if typeSetOf(recv).Len() > 0 {
@ -1253,7 +1252,7 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
case *types.Array, *types.Slice:
var at *types.Array
var array Value
switch t := t.(type) {
switch t := aliases.Unalias(t).(type) {
case *types.Slice:
at = types.NewArray(t.Elem(), b.arrayLen(fn, e.Elts))
array = emitNew(fn, at, e.Lbrace, "slicelit")

Просмотреть файл

@ -25,6 +25,7 @@ import (
"golang.org/x/tools/go/packages"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/ssautil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/testenv"
"golang.org/x/tools/txtar"
)
@ -1091,7 +1092,7 @@ func TestIssue58491Rec(t *testing.T) {
// Find the local type result instantiated with int.
var found bool
for _, rt := range p.Prog.RuntimeTypes() {
if n, ok := rt.(*types.Named); ok {
if n, ok := aliases.Unalias(rt).(*types.Named); ok {
if u, ok := n.Underlying().(*types.Struct); ok {
found = true
if got, want := n.String(), "p.result"; got != want {

Просмотреть файл

@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -47,7 +48,7 @@ func soleTypeKind(typ types.Type) types.BasicInfo {
state := types.IsBoolean | types.IsInteger | types.IsString
underIs(typeSetOf(typ), func(t types.Type) bool {
var c types.BasicInfo
if t, ok := t.(*types.Basic); ok {
if t, ok := aliases.Unalias(t).(*types.Basic); ok {
c = t.Info()
}
if c&types.IsNumeric != 0 { // int/float/complex
@ -113,7 +114,7 @@ func zeroString(t types.Type, from *types.Package) string {
}
case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature:
return "nil"
case *types.Named:
case *types.Named, *aliases.Alias:
return zeroString(t.Underlying(), from)
case *types.Array, *types.Struct:
return relType(t, from) + "{}"

Просмотреть файл

@ -7,6 +7,7 @@ package ssa
import (
"go/types"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -49,7 +50,7 @@ func typeSetOf(typ types.Type) termList {
// This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on.
var terms []*types.Term
var err error
switch typ := typ.(type) {
switch typ := aliases.Unalias(typ).(type) {
case *types.TypeParam:
terms, err = typeparams.StructuralTerms(typ)
case *types.Union:

Просмотреть файл

@ -12,6 +12,7 @@ import (
"go/token"
"go/types"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -184,7 +185,7 @@ func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
// isValuePreserving returns true if a conversion from ut_src to
// ut_dst is value-preserving, i.e. just a change of type.
// Precondition: neither argument is a named type.
// Precondition: neither argument is a named or alias type.
func isValuePreserving(ut_src, ut_dst types.Type) bool {
// Identical underlying types?
if types.IdenticalIgnoreTags(ut_dst, ut_src) {
@ -283,11 +284,11 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
}
// Conversion from slice to array or slice to array pointer?
if slice, ok := s.(*types.Slice); ok {
if slice, ok := aliases.Unalias(s).(*types.Slice); ok {
var arr *types.Array
var ptr bool
// Conversion from slice to array pointer?
switch d := d.(type) {
switch d := aliases.Unalias(d).(type) {
case *types.Array:
arr = d
case *types.Pointer:

Просмотреть файл

@ -17,6 +17,7 @@ import (
"unsafe"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/internal/aliases"
)
// If the target program panics, the interpreter panics with this type.
@ -172,7 +173,7 @@ func asUnsigned(x value) (value, bool) {
// zero returns a new "zero" value of the specified type.
func zero(t types.Type) value {
switch t := t.(type) {
switch t := aliases.Unalias(t).(type) {
case *types.Basic:
if t.Kind() == types.UntypedNil {
panic("untyped nil has no zero value")

Просмотреть файл

@ -18,6 +18,7 @@ import (
"unsafe"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/internal/aliases"
)
type opaqueType struct {
@ -119,7 +120,7 @@ func ext۰reflect۰rtype۰NumField(fr *frame, args []value) value {
func ext۰reflect۰rtype۰NumIn(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.(*types.Signature).Params().Len()
return args[0].(rtype).t.Underlying().(*types.Signature).Params().Len()
}
func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
@ -129,13 +130,13 @@ func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.(*types.Signature).Results().Len()
return args[0].(rtype).t.Underlying().(*types.Signature).Results().Len()
}
func ext۰reflect۰rtype۰Out(fr *frame, args []value) value {
// Signature: func (t reflect.rtype, i int) int
i := args[1].(int)
return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
return makeReflectType(rtype{args[0].(rtype).t.Underlying().(*types.Signature).Results().At(i).Type()})
}
func ext۰reflect۰rtype۰Size(fr *frame, args []value) value {
@ -178,7 +179,7 @@ func ext۰reflect۰Zero(fr *frame, args []value) value {
}
func reflectKind(t types.Type) reflect.Kind {
switch t := t.(type) {
switch t := aliases.Unalias(t).(type) {
case *types.Named:
return reflectKind(t.Underlying())
case *types.Basic:

Просмотреть файл

@ -45,6 +45,7 @@ import (
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
)
type value interface{}
@ -117,7 +118,7 @@ func usesBuiltinMap(t types.Type) bool {
switch t := t.(type) {
case *types.Basic, *types.Chan, *types.Pointer:
return true
case *types.Named:
case *types.Named, *aliases.Alias:
return usesBuiltinMap(t.Underlying())
case *types.Interface, *types.Array, *types.Struct:
return false

Просмотреть файл

@ -11,6 +11,7 @@ import (
"go/types"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -209,6 +210,9 @@ func forEachReachable(msets *typeutil.MethodSetCache, T types.Type, f func(types
}
switch T := T.(type) {
case *aliases.Alias:
visit(aliases.Unalias(T), false)
case *types.Basic:
// nop

Просмотреть файл

@ -8,6 +8,7 @@ import (
"go/types"
"sync"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -48,6 +49,9 @@ func (w *tpWalker) isParameterizedLocked(typ types.Type) (res bool) {
case nil, *types.Basic: // TODO(gri) should nil be handled here?
break
case *aliases.Alias:
return w.isParameterizedLocked(aliases.Unalias(t))
case *types.Array:
return w.isParameterizedLocked(t.Elem())

Просмотреть файл

@ -349,7 +349,7 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) {
// Check that "untyped" types only appear on constant operands.
if _, ok := (*op).(*Const); !ok {
if basic, ok := (*op).Type().(*types.Basic); ok {
if basic, ok := (*op).Type().Underlying().(*types.Basic); ok {
if basic.Info()&types.IsUntyped != 0 {
s.errorf("operand #%d of %s is untyped: %s", i, instr, basic)
}

Просмотреть файл

@ -6,6 +6,8 @@ package ssa
import (
"go/types"
"golang.org/x/tools/internal/aliases"
)
// Type substituter for a fixed set of replacement types.
@ -80,6 +82,9 @@ func (subst *subster) typ(t types.Type) (res types.Type) {
// fall through if result r will be identical to t, types.Identical(r, t).
switch t := t.(type) {
case *aliases.Alias:
return subst.typ(aliases.Unalias(t))
case *types.TypeParam:
r := subst.replacements[t]
assert(r != nil, "type param without replacement encountered")
@ -466,7 +471,7 @@ func reaches(t types.Type, c map[types.Type]bool) (res bool) {
return true
}
}
case *types.Named:
case *types.Named, *aliases.Alias:
return reaches(t.Underlying(), c)
default:
panic("unreachable")

Просмотреть файл

@ -17,6 +17,7 @@ import (
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
)
@ -51,16 +52,19 @@ func isNonTypeParamInterface(t types.Type) bool {
// isBasic reports whether t is a basic type.
func isBasic(t types.Type) bool {
_, ok := t.(*types.Basic)
_, ok := aliases.Unalias(t).(*types.Basic)
return ok
}
// isString reports whether t is exactly a string type.
// t is assumed to be an Underlying type (not Named or Alias).
func isString(t types.Type) bool {
return isBasic(t) && t.(*types.Basic).Info()&types.IsString != 0
basic, ok := t.(*types.Basic)
return ok && basic.Info()&types.IsString != 0
}
// isByteSlice reports whether t is of the form []~bytes.
// t is assumed to be an Underlying type (not Named or Alias).
func isByteSlice(t types.Type) bool {
if b, ok := t.(*types.Slice); ok {
e, _ := b.Elem().Underlying().(*types.Basic)
@ -70,6 +74,7 @@ func isByteSlice(t types.Type) bool {
}
// isRuneSlice reports whether t is of the form []~runes.
// t is assumed to be an Underlying type (not Named or Alias).
func isRuneSlice(t types.Type) bool {
if b, ok := t.(*types.Slice); ok {
e, _ := b.Elem().Underlying().(*types.Basic)
@ -131,8 +136,9 @@ func fieldOf(typ types.Type, index int) *types.Var {
return nil
}
// isUntyped returns true for types that are untyped.
// isUntyped reports whether typ is the type of an untyped constant.
func isUntyped(typ types.Type) bool {
// No Underlying/Unalias: untyped constant types cannot be Named or Alias.
b, ok := typ.(*types.Basic)
return ok && b.Info()&types.IsUntyped != 0
}
@ -342,10 +348,10 @@ func (m *typeListMap) hash(ts []types.Type) uint32 {
// instantiateMethod instantiates m with targs and returns a canonical representative for this method.
func (canon *canonizer) instantiateMethod(m *types.Func, targs []types.Type, ctxt *types.Context) *types.Func {
recv := recvType(m)
if p, ok := recv.(*types.Pointer); ok {
if p, ok := aliases.Unalias(recv).(*types.Pointer); ok {
recv = p.Elem()
}
named := recv.(*types.Named)
named := aliases.Unalias(recv).(*types.Named)
inst, err := types.Instantiate(ctxt, named.Origin(), targs, false)
if err != nil {
panic(err)

Просмотреть файл

@ -32,6 +32,7 @@ import (
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/go/types/typeutil"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
)
@ -285,7 +286,7 @@ func formatObj(out *strings.Builder, fset *token.FileSet, ref string, obj types.
if obj.IsAlias() {
kind = "type alias"
}
if named, ok := obj.Type().(*types.Named); ok {
if named, ok := aliases.Unalias(obj.Type()).(*types.Named); ok {
origin = named.Obj()
}
}

Просмотреть файл

@ -29,10 +29,13 @@ import (
"strconv"
"strings"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typeparams"
"golang.org/x/tools/internal/typesinternal"
)
// TODO(adonovan): think about generic aliases.
// A Path is an opaque name that identifies a types.Object
// relative to its package. Conceptually, the name consists of a
// sequence of destructuring operations applied to the package scope
@ -224,7 +227,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
// Reject obviously non-viable cases.
switch obj := obj.(type) {
case *types.TypeName:
if _, ok := obj.Type().(*types.TypeParam); !ok {
if _, ok := aliases.Unalias(obj.Type()).(*types.TypeParam); !ok {
// With the exception of type parameters, only package-level type names
// have a path.
return "", fmt.Errorf("no path for %v", obj)
@ -311,7 +314,7 @@ func (enc *Encoder) For(obj types.Object) (Path, error) {
}
// Inspect declared methods of defined types.
if T, ok := o.Type().(*types.Named); ok {
if T, ok := aliases.Unalias(o.Type()).(*types.Named); ok {
path = append(path, opType)
// The method index here is always with respect
// to the underlying go/types data structures,
@ -440,6 +443,8 @@ func (enc *Encoder) concreteMethod(meth *types.Func) (Path, bool) {
// nil, it will be allocated as necessary.
func find(obj types.Object, T types.Type, path []byte, seen map[*types.TypeName]bool) []byte {
switch T := T.(type) {
case *aliases.Alias:
return find(obj, aliases.Unalias(T), path, seen)
case *types.Basic, *types.Named:
// Named types belonging to pkg were handled already,
// so T must belong to another package. No path.
@ -612,6 +617,7 @@ func Object(pkg *types.Package, p Path) (types.Object, error) {
// Inv: t != nil, obj == nil
t = aliases.Unalias(t)
switch code {
case opElem:
hasElem, ok := t.(hasElem) // Pointer, Slice, Array, Chan, Map

Просмотреть файл

@ -6,7 +6,11 @@ package typeutil
// This file defines utilities for user interfaces that display types.
import "go/types"
import (
"go/types"
"golang.org/x/tools/internal/aliases"
)
// IntuitiveMethodSet returns the intuitive method set of a type T,
// which is the set of methods you can call on an addressable value of
@ -24,7 +28,7 @@ import "go/types"
// The order of the result is as for types.MethodSet(T).
func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection {
isPointerToConcrete := func(T types.Type) bool {
ptr, ok := T.(*types.Pointer)
ptr, ok := aliases.Unalias(T).(*types.Pointer)
return ok && !types.IsInterface(ptr.Elem())
}

Просмотреть файл

@ -13,6 +13,8 @@ import (
"go/token"
"go/types"
"strconv"
"golang.org/x/tools/internal/aliases"
)
func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
@ -28,7 +30,10 @@ func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos
}
func ZeroValue(f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
under := typ
// TODO(adonovan): think about generics, and also generic aliases.
under := aliases.Unalias(typ)
// Don't call Underlying unconditionally: although it removed
// Named and Alias, it also removes TypeParam.
if n, ok := typ.(*types.Named); ok {
under = n.Underlying()
}

Просмотреть файл

@ -18,6 +18,7 @@ import (
"golang.org/x/tools/go/analysis/analysistest"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/facts"
"golang.org/x/tools/internal/testenv"
)
@ -360,7 +361,7 @@ func find(p *types.Package, expr string) types.Object {
if err != nil {
return nil
}
if n, ok := tv.Type.(*types.Named); ok {
if n, ok := aliases.Unalias(tv.Type).(*types.Named); ok {
return n.Obj()
}
return nil

Просмотреть файл

@ -6,6 +6,8 @@ package facts
import (
"go/types"
"golang.org/x/tools/internal/aliases"
)
// importMap computes the import map for a package by traversing the
@ -45,6 +47,8 @@ func importMap(imports []*types.Package) map[string]*types.Package {
addType = func(T types.Type) {
switch T := T.(type) {
case *aliases.Alias:
addType(aliases.Unalias(T))
case *types.Basic:
// nop
case *types.Named:

Просмотреть файл

@ -18,6 +18,7 @@ import (
"strings"
"testing"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/gcimporter"
)
@ -30,6 +31,8 @@ func fileLine(fset *token.FileSet, obj types.Object) string {
}
func equalType(x, y types.Type) error {
x = aliases.Unalias(x)
y = aliases.Unalias(y)
if reflect.TypeOf(x) != reflect.TypeOf(y) {
return fmt.Errorf("unequal kinds: %T vs %T", x, y)
}

Просмотреть файл

@ -28,6 +28,7 @@ import (
"testing"
"time"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/goroot"
"golang.org/x/tools/internal/testenv"
)
@ -438,7 +439,7 @@ func TestImportedTypes(t *testing.T) {
t.Errorf("%s: got %q; want %q", test.name, got, test.want)
}
if named, _ := obj.Type().(*types.Named); named != nil {
if named, _ := aliases.Unalias(obj.Type()).(*types.Named); named != nil {
verifyInterfaceMethodRecvs(t, named, 0)
}
}
@ -521,7 +522,7 @@ func verifyInterfaceMethodRecvs(t *testing.T, named *types.Named, level int) {
// check embedded interfaces (if they are named, too)
for i := 0; i < iface.NumEmbeddeds(); i++ {
// embedding of interfaces cannot have cycles; recursion will terminate
if etype, _ := iface.EmbeddedType(i).(*types.Named); etype != nil {
if etype, _ := aliases.Unalias(iface.EmbeddedType(i)).(*types.Named); etype != nil {
verifyInterfaceMethodRecvs(t, etype, level+1)
}
}
@ -541,7 +542,7 @@ func TestIssue5815(t *testing.T) {
t.Errorf("no pkg for %s", obj)
}
if tname, _ := obj.(*types.TypeName); tname != nil {
named := tname.Type().(*types.Named)
named := aliases.Unalias(tname.Type()).(*types.Named)
for i := 0; i < named.NumMethods(); i++ {
m := named.Method(i)
if m.Pkg() == nil {
@ -641,7 +642,7 @@ func TestIssue13898(t *testing.T) {
// look for go/types.Object type
obj := lookupObj(t, goTypesPkg.Scope(), "Object")
typ, ok := obj.Type().(*types.Named)
typ, ok := aliases.Unalias(obj.Type()).(*types.Named)
if !ok {
t.Fatalf("go/types.Object type is %v; wanted named type", typ)
}

Просмотреть файл

@ -23,6 +23,7 @@ import (
"strings"
"golang.org/x/tools/go/types/objectpath"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/tokeninternal"
)
@ -506,13 +507,13 @@ func (p *iexporter) doDecl(obj types.Object) {
case *types.TypeName:
t := obj.Type()
if tparam, ok := t.(*types.TypeParam); ok {
if tparam, ok := aliases.Unalias(t).(*types.TypeParam); ok {
w.tag('P')
w.pos(obj.Pos())
constraint := tparam.Constraint()
if p.version >= iexportVersionGo1_18 {
implicit := false
if iface, _ := constraint.(*types.Interface); iface != nil {
if iface, _ := aliases.Unalias(constraint).(*types.Interface); iface != nil {
implicit = iface.IsImplicit()
}
w.bool(implicit)
@ -738,6 +739,8 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
}()
}
switch t := t.(type) {
// TODO(adonovan): support types.Alias.
case *types.Named:
if targs := t.TypeArgs(); targs.Len() > 0 {
w.startType(instanceType)
@ -843,7 +846,7 @@ func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
for i := 0; i < n; i++ {
ft := t.EmbeddedType(i)
tPkg := pkg
if named, _ := ft.(*types.Named); named != nil {
if named, _ := aliases.Unalias(ft).(*types.Named); named != nil {
w.pos(named.Obj().Pos())
} else {
w.pos(token.NoPos)

Просмотреть файл

@ -22,6 +22,7 @@ import (
"strings"
"golang.org/x/tools/go/types/objectpath"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typesinternal"
)
@ -523,7 +524,7 @@ func canReuse(def *types.Named, rhs types.Type) bool {
if def == nil {
return true
}
iface, _ := rhs.(*types.Interface)
iface, _ := aliases.Unalias(rhs).(*types.Interface)
if iface == nil {
return true
}
@ -594,7 +595,7 @@ func (r *importReader) obj(name string) {
if targs.Len() > 0 {
rparams = make([]*types.TypeParam, targs.Len())
for i := range rparams {
rparams[i] = targs.At(i).(*types.TypeParam)
rparams[i] = aliases.Unalias(targs.At(i)).(*types.TypeParam)
}
}
msig := r.signature(recv, rparams, nil)
@ -624,7 +625,7 @@ func (r *importReader) obj(name string) {
}
constraint := r.typ()
if implicit {
iface, _ := constraint.(*types.Interface)
iface, _ := aliases.Unalias(constraint).(*types.Interface)
if iface == nil {
errorf("non-interface constraint marked implicit")
}
@ -831,7 +832,7 @@ func (r *importReader) typ() types.Type {
}
func isInterface(t types.Type) bool {
_, ok := t.(*types.Interface)
_, ok := aliases.Unalias(t).(*types.Interface)
return ok
}
@ -1030,7 +1031,7 @@ func (r *importReader) tparamList() []*types.TypeParam {
for i := range xs {
// Note: the standard library importer is tolerant of nil types here,
// though would panic in SetTypeParams.
xs[i] = r.typ().(*types.TypeParam)
xs[i] = aliases.Unalias(r.typ()).(*types.TypeParam)
}
return xs
}

Просмотреть файл

@ -16,6 +16,7 @@ import (
"sort"
"strings"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/pkgbits"
)
@ -553,7 +554,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
// If the underlying type is an interface, we need to
// duplicate its methods so we can replace the receiver
// parameter's type (#49906).
if iface, ok := underlying.(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
if iface, ok := aliases.Unalias(underlying).(*types.Interface); ok && iface.NumExplicitMethods() != 0 {
methods := make([]*types.Func, iface.NumExplicitMethods())
for i := range methods {
fn := iface.ExplicitMethod(i)

Просмотреть файл

@ -28,6 +28,7 @@ import (
"go/token"
"go/types"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/internal/typesinternal"
)
@ -74,9 +75,9 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, indices []ast.Expr, rbrack toke
}
}
// IsTypeParam reports whether t is a type parameter.
// IsTypeParam reports whether t is a type parameter (or an alias of one).
func IsTypeParam(t types.Type) bool {
_, ok := t.(*types.TypeParam)
_, ok := aliases.Unalias(t).(*types.TypeParam)
return ok
}
@ -155,6 +156,9 @@ func OriginMethod(fn *types.Func) *types.Func {
// In this case, GenericAssignableTo reports that instantiations of Container
// are assignable to the corresponding instantiation of Interface.
func GenericAssignableTo(ctxt *types.Context, V, T types.Type) bool {
V = aliases.Unalias(V)
T = aliases.Unalias(T)
// If V and T are not both named, or do not have matching non-empty type
// parameter lists, fall back on types.AssignableTo.

Просмотреть файл

@ -7,6 +7,8 @@ package typeparams
import (
"fmt"
"go/types"
"golang.org/x/tools/internal/aliases"
)
// CoreType returns the core type of T or nil if T does not have a core type.
@ -110,7 +112,7 @@ func CoreType(T types.Type) types.Type {
// _NormalTerms makes no guarantees about the order of terms, except that it
// is deterministic.
func _NormalTerms(typ types.Type) ([]*types.Term, error) {
switch typ := typ.(type) {
switch typ := aliases.Unalias(typ).(type) {
case *types.TypeParam:
return StructuralTerms(typ)
case *types.Union:

Просмотреть файл

@ -12,6 +12,7 @@ import (
"strings"
"golang.org/x/tools/go/ast/inspector"
"golang.org/x/tools/internal/aliases"
)
// Features is a set of flags reporting which features of generic Go code a
@ -92,7 +93,7 @@ func ForPackage(inspect *inspector.Inspector, info *types.Info) Features {
})
for _, inst := range info.Instances {
switch inst.Type.(type) {
switch aliases.Unalias(inst.Type).(type) {
case *types.Named:
direct |= TypeInstantiation
case *types.Signature:

Просмотреть файл

@ -13,6 +13,7 @@ import (
"go/types"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/internal/aliases"
"golang.org/x/tools/refactor/satisfy"
)
@ -467,9 +468,10 @@ func (r *renamer) checkStructField(from *types.Var) {
// type T int // this and
// var s struct {T} // this must change too.
if from.Anonymous() {
if named, ok := from.Type().(*types.Named); ok {
// TODO(adonovan): think carefully about aliases.
if named, ok := aliases.Unalias(from.Type()).(*types.Named); ok {
r.check(named.Obj())
} else if named, ok := deref(from.Type()).(*types.Named); ok {
} else if named, ok := aliases.Unalias(deref(from.Type())).(*types.Named); ok {
r.check(named.Obj())
}
}
@ -777,7 +779,7 @@ func (r *renamer) checkMethod(from *types.Func) {
var iface string
I := recv(imeth).Type()
if named, ok := I.(*types.Named); ok {
if named, ok := aliases.Unalias(I).(*types.Named); ok {
pos = named.Obj().Pos()
iface = "interface " + named.Obj().Name()
} else {
@ -851,7 +853,7 @@ func someUse(info *loader.PackageInfo, obj types.Object) *ast.Ident {
func isInterface(T types.Type) bool { return types.IsInterface(T) }
func deref(typ types.Type) types.Type {
if p, _ := typ.(*types.Pointer); p != nil {
if p, _ := aliases.Unalias(typ).(*types.Pointer); p != nil {
return p.Elem()
}
return typ

Просмотреть файл

@ -25,6 +25,7 @@ import (
"golang.org/x/tools/go/buildutil"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/internal/aliases"
)
// A spec specifies an entity to rename.
@ -465,9 +466,9 @@ func findObjects(info *loader.PackageInfo, spec *spec) ([]types.Object, error) {
if spec.searchFor == "" {
// If it is an embedded field, return the type of the field.
if v, ok := obj.(*types.Var); ok && v.Anonymous() {
switch t := v.Type().(type) {
switch t := aliases.Unalias(v.Type()).(type) {
case *types.Pointer:
return []types.Object{t.Elem().(*types.Named).Obj()}, nil
return []types.Object{aliases.Unalias(t.Elem()).(*types.Named).Obj()}, nil
case *types.Named:
return []types.Object{t.Obj()}, nil
}