@@ -53,79 +53,87 @@ func TypeString(typ Type, qf Qualifier) string {
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteType ( buf * bytes . Buffer , typ Type , qf Qualifier ) {
writeType ( buf , typ , qf , make ( [ ] T ype , 0 , 8 ) )
newTypeWriter ( buf , qf ) . typ ( t yp)
}
// instanceMarker is the prefix for an instantiated type
// in "non-evaluated" instance form.
// instanceMarker is the prefix for an instantiated type in unexpanded form.
const instanceMarker = '#'
func writeType ( buf * bytes . Buffer , typ Type , qf Qualifier , visited [ ] Type ) {
// Theoretically, this is a quadratic lookup algorithm, but in
// practice deeply nested composite types with unnamed component
// types are uncommon. This code is likely more efficient than
// using a map.
for _ , t := range visited {
if t == typ {
fmt . Fprintf ( buf , "○%T" , goTypeName ( typ ) ) // cycle to typ
return
}
type typeWriter struct {
buf * bytes . Buffer
seen map [ Type ] bool
qf Qualifier
}
func newTypeWriter ( buf * bytes . Buffer , qf Qualifier ) * typeWriter {
return & typeWriter { buf , make ( map [ Type ] bool ) , qf }
}
func ( w * typeWriter ) byte ( b byte ) { w . buf . WriteByte ( b ) }
func ( w * typeWriter ) string ( s string ) { w . buf . WriteString ( s ) }
func ( w * typeWriter ) writef ( format string , args ... interface { } ) { fmt . Fprintf ( w . buf , format , args ... ) }
func ( w * typeWriter ) typ ( typ Type ) {
if w . seen [ typ ] {
w . writef ( "○%T" , goTypeName ( typ ) ) // cycle to typ
return
}
visited = app end ( visited , typ )
w . se en[ typ ] = true
defer delete ( w . seen , typ )
switch t := typ . ( type ) {
case nil :
buf . WriteS tring( "<nil>" )
w . s tring( "<nil>" )
case * Basic :
// exported basic types go into package unsafe
// (currently this is just unsafe.Pointer)
if token . IsExported ( t . name ) {
if obj , _ := Unsafe . scope . Lookup ( t . name ) . ( * TypeName ) ; obj != nil {
writeT ypeName( buf , obj , qf )
w . t ypeName( obj )
break
}
}
buf . WriteS tring( t . name )
w . s tring( t . name )
case * Array :
fmt . Fprintf ( buf , "[%d]" , t . len )
writeT ype ( buf , t . elem , qf , visited )
w . writef ( "[%d]" , t . len )
w . t yp( t . elem )
case * Slice :
buf . WriteS tring( "[]" )
writeT ype ( buf , t . elem , qf , visited )
w . s tring( "[]" )
w . t yp( t . elem )
case * Struct :
buf . WriteS tring( "struct{" )
w . s tring( "struct{" )
for i , f := range t . fields {
if i > 0 {
buf . WriteS tring( "; " )
w . s tring( "; " )
}
// This doesn't do the right thing for embedded type
// aliases where we should print the alias name, not
// the aliased type (see issue #44410).
if ! f . embedded {
buf . WriteS tring( f . name )
buf . WriteB yte( ' ' )
w . s tring( f . name )
w . b yte( ' ' )
}
writeType ( buf , f . typ, q f, visited )
w . typ( f . typ )
if tag := t . Tag ( i ) ; tag != "" {
fmt . Fprintf ( buf , " %q" , tag )
w . writef ( " %q" , tag )
}
}
buf . WriteB yte( '}' )
w . b yte( '}' )
case * Pointer :
buf . WriteB yte( '*' )
writeT ype ( buf , t . base , qf , visited )
w . b yte( '*' )
w . t yp( t . base )
case * Tuple :
writeT uple( buf , t, false , qf , visited )
w . t uple( t , false )
case * Signature :
buf . WriteS tring( "func" )
writeS ignature( buf , t , qf , visited )
w . s tring( "func" )
w . s ignature( t )
case * Union :
// Unions only appear as (syntactic) embedded elements
@@ -135,40 +143,39 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
}
for i , t := range t . terms {
if i > 0 {
buf . WriteB yte( '|' )
w . b yte( '|' )
}
if t . tilde {
buf . WriteB yte( '~' )
w . b yte( '~' )
}
writeT ype ( buf , t . typ , qf , visited )
w . t yp( t . typ )
}
case * Interface :
buf . WriteS tring( "interface{" )
w . s tring( "interface{" )
first := true
// print explicit interface methods and embedded types
for _ , m := range t . methods {
if ! first {
buf . WriteS tring( "; " )
w . s tring( "; " )
}
first = false
buf . WriteS tring( m . name )
writeS ignature(buf , m . typ . ( * Signature ) , qf , visited )
w . s tring( m . name )
w . s ignature( m . typ . ( * Signature ) )
}
for _ , typ := range t . embeddeds {
if ! first {
buf . WriteS tring( "; " )
w . s tring( "; " )
}
first = false
writeType ( buf , typ , qf , visited )
w . typ ( typ )
}
buf . WriteB yte( '}' )
w . b yte( '}' )
case * Map :
buf . WriteS tring( "map[" )
writeT ype ( buf , t . key , qf , visited )
buf . WriteB yte( ']' )
writeT ype ( buf , t . elem , qf , visited )
w . s tring( "map[" )
w . t yp( t . key )
w . b yte( ']' )
w . t yp( t . elem )
case * Chan :
var s string
@@ -187,66 +194,65 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
default :
unreachable ( )
}
buf . WriteS tring( s )
w . s tring( s )
if parens {
buf . WriteB yte( '(' )
w . b yte( '(' )
}
writeT ype ( buf , t . elem , qf , visited )
w . t yp( t . elem )
if parens {
buf . WriteB yte( ')' )
w . b yte( ')' )
}
case * Named :
if t . instPos != nil {
buf . WriteB yte( instanceMarker )
w . b yte( instanceMarker )
}
writeT ypeName( buf , t . obj , qf )
w . t ypeName( t . obj )
if t . targs != nil {
// instantiated type
buf . WriteByte ( '[' )
writeTypeList ( buf , t . targs . list ( ) , qf , visited )
buf . WriteByte ( ']' )
w . typeList ( t . targs . list ( ) )
} else if t . TParams ( ) . Len ( ) != 0 {
// parameterized type
writeT ParamList(buf , t . TParams ( ) . list ( ) , qf , visited )
w . t ParamList( t . TParams ( ) . list ( ) )
}
case * TypeParam :
s := "?"
if t . obj != nil {
// Optionally write out package for typeparams (like Named).
// TODO(rfind ley ): this is required for import/export, so
// TODO(dansca les ): this is required for import/export, so
// we maybe need a separate function that won't be changed
// for debugging purposes.
if t . obj . pkg != nil {
writePackage ( buf , t . obj . pkg , qf )
writePackage ( w . buf, t . obj . pkg , w . qf )
}
s = t . obj . name
}
buf . WriteS tring( s + subscript ( t . id ) )
w . s tring( s + subscript ( t . id ) )
case * top :
buf . WriteS tring( "⊤ " )
w . s tring( "⊤ " )
default :
// For externally defined implementations of Type.
// Note: In this case cycles won't be caught.
buf . WriteS tring( t . String ( ) )
w . s tring( t . String ( ) )
}
}
func writeTypeList ( buf * bytes . Buff er, list [ ] Type , qf Qualifier , v isited [ ] Type ) {
func ( w * typeWrit er) typeList ( l ist [ ] Type ) {
w . byte ( '[' )
for i , typ := range list {
if i > 0 {
buf . WriteS tring( ", " )
w . s tring( ", " )
}
writeType ( buf , typ , qf , visited )
w . typ ( typ )
}
w . byte ( ']' )
}
func writeTParamList ( buf * bytes . Buff er, list [ ] * TypeParam , qf Qualifier , v isited [ ] Type ) {
// TODO(rFindley) compare this with the corresponding implementation in types2
buf . WriteString ( "[" )
func ( w * typeWrit er) tParamList ( l ist [ ] * TypeParam ) {
w . byte ( '[' )
var prev Type
for i , tpar := range list {
// Determine the type parameter and its constraint.
@@ -260,35 +266,36 @@ func writeTParamList(buf *bytes.Buffer, list []*TypeParam, qf Qualifier, visited
if i > 0 {
if bound != prev {
// bound changed - write previous one before advancing
buf . WriteB yte( ' ' )
writeT ype ( buf , prev , qf , visited )
w . b yte( ' ' )
w . t yp( prev )
}
buf . WriteS tring( ", " )
w . s tring( ", " )
}
prev = bound
if tpar != nil {
writeT ype ( buf , tpar , qf , visited )
w . t yp( tpar )
} else {
buf . WriteS tring( tpar . obj . name )
w . s tring( tpar . obj . name )
}
}
if prev != nil {
buf . WriteB yte( ' ' )
writeT ype ( buf , prev , qf , visited )
w . b yte( ' ' )
w . t yp( prev )
}
buf . WriteB yte( ']' )
w . b yte( ']' )
}
func writeTypeName ( buf * bytes . Buff er, obj * TypeName , qf Qualifier ) {
func ( w * typeWrit er) typeName ( obj * TypeName ) {
if obj == nil {
buf . WriteString ( "<Named w/o object>" )
assert ( instanceHashing == 0 ) // we need an object for instance hashing
w . string ( "<Named w/o object>" )
return
}
if obj . pkg != nil {
writePackage ( buf , obj . pkg , qf )
writePackage ( w . buf, obj . pkg , w . qf )
}
buf . WriteS tring( obj . name )
w . s tring( obj . name )
if instanceHashing != 0 {
// For local defined types, use the (original!) TypeName's scope
@@ -300,7 +307,7 @@ func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
for typ . orig != typ {
typ = typ . orig
}
writeScopeNumbers (buf , typ . obj . parent )
w . writeScopeNumbers ( typ . obj . parent )
}
}
@@ -308,28 +315,28 @@ func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
// in the form ".i.j.k" where i, j, k, etc. stand for scope numbers.
// If a scope is nil or has no parent (such as a package scope), nothing
// is written.
func writeScopeNumbers ( buf * by tes . Buff er, s * Scope ) {
func ( w * typeWri ter ) writeScopeNumb ers ( s * Scope ) {
if s != nil && s . number > 0 {
writeScopeNumbers (buf , s . parent )
fmt . Fprintf ( buf , ".%d" , s . number )
w . writeScopeNumbers ( s . parent )
w . writef ( ".%d" , s . number )
}
}
func writeTuple ( buf * by tes . Buffer , tup * Tuple , variadic bool , qf Qualifier , visited [ ] Type ) {
buf . WriteB yte( '(' )
func ( w * typeWri ter ) tuple ( tup * Tuple , variadic bool ) {
w . b yte( '(' )
if tup != nil {
for i , v := range tup . vars {
if i > 0 {
buf . WriteS tring( ", " )
w . s tring( ", " )
}
if v . name != "" {
buf . WriteS tring( v . name )
buf . WriteB yte( ' ' )
w . s tring( v . name )
w . b yte( ' ' )
}
typ := v . typ
if variadic && i == len ( tup . vars ) - 1 {
if s , ok := typ . ( * Slice ) ; ok {
buf . WriteS tring( "..." )
w . s tring( "..." )
typ = s . elem
} else {
// special case:
@@ -337,15 +344,15 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
if t := asBasic ( typ ) ; t == nil || t . kind != String {
panic ( "expected string type" )
}
writeType ( buf , typ , qf , visited )
buf . WriteS tring( "..." )
w . typ ( typ )
w . s tring( "..." )
continue
}
}
writeType ( buf , typ , qf , visited )
w . typ ( typ )
}
}
buf . WriteB yte( ')' )
w . b yte( ')' )
}
// WriteSignature writes the representation of the signature sig to buf,
@@ -353,15 +360,15 @@ func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visi
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteSignature ( buf * bytes . Buffer , sig * Signature , qf Qualifier ) {
writeSignature ( buf , sig , qf , make ( [ ] Type , 0 , 8 ) )
newTypeWriter ( buf , qf ) . signature ( sig )
}
func writeSignature ( buf * bytes . Buff er, sig * Signature , qf Qualifier , visited [ ] Typ e ) {
func ( w * typeWrit er) signature ( sig * Signature ) {
if sig . TParams ( ) . Len ( ) != 0 {
writeT ParamList(buf , sig . TParams ( ) . list ( ) , qf , visited )
w . t ParamList( sig . TParams ( ) . list ( ) )
}
writeTuple ( buf , sig . params , sig . variadic , qf , visited )
w . tuple ( sig . params , sig . variadic )
n := sig . results . Len ( )
if n == 0 {
@@ -369,15 +376,15 @@ func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []T
return
}
buf . WriteB yte( ' ' )
w . b yte( ' ' )
if n == 1 && sig . results . vars [ 0 ] . name == "" {
// single unnamed result
writeT ype (buf , sig . results . vars [ 0 ] . typ , qf , visited )
w . t yp( sig . results . vars [ 0 ] . typ )
return
}
// multiple or named result(s)
writeTuple ( buf , sig . results , false , qf , visited )
w . tuple ( sig . results , false )
}
// subscript returns the decimal (utf8) representation of x using subscript digits.