Commit aa1f0681 authored by Robert Griesemer's avatar Robert Griesemer

[dev.typealias] go/types: improved Object printing

- added internal isAlias predicated and test
- use it for improved Object printing
- when printing a basic type object, don't repeat type name
  (i.e., print "type int" rather than "type int int")
- added another test to testdata/decls4.src

For #18130.

Change-Id: Ice9517c0065a2cc465c6d12f87cd27c01ef801e6
Reviewed-on: https://go-review.googlesource.com/35093
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent c80748e3
......@@ -239,10 +239,10 @@ func fib(x int) int {
// type S string:
// defined at fib.go:4:6
// used at 6:23
// type int int:
// type int:
// defined at -
// used at 8:12, 8:17
// type string string:
// type string:
// defined at -
// used at 4:8
// var b S:
......
......@@ -163,6 +163,30 @@ func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
}
func (obj *TypeName) isAlias() bool {
switch t := obj.typ.(type) {
case nil:
return false
case *Basic:
// It would seem that we should be able to look for different names here;
// but the names of universeByte/Rune are "byte" and "rune", respectively.
// We do this so that we get better error messages. However, general alias
// types don't have that name information and thus behave differently when
// reporting errors (we won't see the alias name, only the original name).
// Maybe we should remove the special handling for the predeclared types
// as well to be consistent (at the cost of slightly less clear error
// messages when byte/rune are involved).
// This also plays out in the implementation of the Identical(Type, Type)
// predicate.
// TODO(gri) consider possible clean up
return t == universeByte || t == universeRune
case *Named:
return obj != t.obj
default:
return true
}
}
// A Variable represents a declared variable (including function parameters and results, and struct fields).
type Var struct {
object
......@@ -242,7 +266,9 @@ type Nil struct {
}
func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
var tname *TypeName
typ := obj.Type()
switch obj := obj.(type) {
case *PkgName:
fmt.Fprintf(buf, "package %s", obj.Name())
......@@ -255,8 +281,8 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
buf.WriteString("const")
case *TypeName:
tname = obj
buf.WriteString("type")
typ = typ.Underlying()
case *Var:
if obj.isField {
......@@ -297,12 +323,26 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
}
buf.WriteString(obj.Name())
// TODO(gri) indicate type alias if we have one
if typ == nil {
return
}
if tname != nil {
// We have a type object: Don't print anything more for
// basic types since there's no more information (names
// are the same; see also comment in TypeName.isAlias).
if _, ok := typ.(*Basic); ok {
return
}
if tname.isAlias() {
buf.WriteString(" =")
} else {
typ = typ.Underlying()
}
}
if typ != nil {
buf.WriteByte(' ')
WriteType(buf, typ, qf)
}
}
func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
......
// Copyright 2016 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 types
import "testing"
func TestIsAlias(t *testing.T) {
check := func(obj *TypeName, want bool) {
if got := obj.isAlias(); got != want {
t.Errorf("%v: got isAlias = %v; want %v", obj, got, want)
}
}
// predeclared types
for _, name := range Universe.Names() {
if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
check(obj, name == "byte" || name == "rune")
}
}
// various other types
t0 := NewTypeName(0, nil, "t0", nil)
check(t0, false) // no type yet
t1 := NewTypeName(0, nil, "t1", nil)
n1 := NewNamed(t1, new(Struct), nil)
check(t1, false) // type name refers to named type and vice versa
t2 := NewTypeName(0, nil, "t2", new(Interface))
check(t2, true) // type name refers to unnamed type
t3 := NewTypeName(0, nil, "t3", n1)
check(t3, true) // type name refers to named type with different type name (true alias)
}
......@@ -139,7 +139,7 @@ func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
case *Basic:
// Basic types are singletons except for the rune and byte
// aliases, thus we cannot solely rely on the x == y check
// above.
// above. See also comment in TypeName.isAlias.
if y, ok := y.(*Basic); ok {
return x.kind == y.kind
}
......
......@@ -63,6 +63,7 @@ func (Ai /* ERROR "invalid receiver" */) m1() {}
func (T0) m1() {}
func (A0) m1 /* ERROR already declared */ () {}
func (A0) m2 () {}
func (A3 /* ERROR invalid receiver */ ) m1 () {}
func (A10 /* ERROR invalid receiver */ ) m1() {}
// x0 has methods m1, m2 declared via receiver type names T0 and A0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment