@@ -152,6 +152,27 @@ func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value {
152152 return structGlobal
153153}
154154
155+ var basicTypes = [... ]string {
156+ types .Bool : "bool" ,
157+ types .Int : "int" ,
158+ types .Int8 : "int8" ,
159+ types .Int16 : "int16" ,
160+ types .Int32 : "int32" ,
161+ types .Int64 : "int64" ,
162+ types .Uint : "uint" ,
163+ types .Uint8 : "uint8" ,
164+ types .Uint16 : "uint16" ,
165+ types .Uint32 : "uint32" ,
166+ types .Uint64 : "uint64" ,
167+ types .Uintptr : "uintptr" ,
168+ types .Float32 : "float32" ,
169+ types .Float64 : "float64" ,
170+ types .Complex64 : "complex64" ,
171+ types .Complex128 : "complex128" ,
172+ types .String : "string" ,
173+ types .UnsafePointer : "unsafe.Pointer" ,
174+ }
175+
155176// getTypeCodeName returns a name for this type that can be used in the
156177// interface lowering pass to assign type codes as expected by the reflect
157178// package. See getTypeCodeNum.
@@ -162,48 +183,7 @@ func getTypeCodeName(t types.Type) string {
162183 case * types.Array :
163184 return "array:" + strconv .FormatInt (t .Len (), 10 ) + ":" + getTypeCodeName (t .Elem ())
164185 case * types.Basic :
165- var kind string
166- switch t .Kind () {
167- case types .Bool :
168- kind = "bool"
169- case types .Int :
170- kind = "int"
171- case types .Int8 :
172- kind = "int8"
173- case types .Int16 :
174- kind = "int16"
175- case types .Int32 :
176- kind = "int32"
177- case types .Int64 :
178- kind = "int64"
179- case types .Uint :
180- kind = "uint"
181- case types .Uint8 :
182- kind = "uint8"
183- case types .Uint16 :
184- kind = "uint16"
185- case types .Uint32 :
186- kind = "uint32"
187- case types .Uint64 :
188- kind = "uint64"
189- case types .Uintptr :
190- kind = "uintptr"
191- case types .Float32 :
192- kind = "float32"
193- case types .Float64 :
194- kind = "float64"
195- case types .Complex64 :
196- kind = "complex64"
197- case types .Complex128 :
198- kind = "complex128"
199- case types .String :
200- kind = "string"
201- case types .UnsafePointer :
202- kind = "unsafeptr"
203- default :
204- panic ("unknown basic type: " + t .Name ())
205- }
206- return "basic:" + kind
186+ return "basic:" + basicTypes [t .Kind ()]
207187 case * types.Chan :
208188 return "chan:" + getTypeCodeName (t .Elem ())
209189 case * types.Interface :
@@ -591,23 +571,77 @@ func signature(sig *types.Signature) string {
591571 if i > 0 {
592572 s += ", "
593573 }
594- s += sig .Params ().At (i ).Type (). String ( )
574+ s += typestring ( sig .Params ().At (i ).Type ())
595575 }
596576 s += ")"
597577 }
598578 if sig .Results ().Len () == 0 {
599579 // keep as-is
600580 } else if sig .Results ().Len () == 1 {
601- s += " " + sig .Results ().At (0 ).Type (). String ( )
581+ s += " " + typestring ( sig .Results ().At (0 ).Type ())
602582 } else {
603583 s += " ("
604584 for i := 0 ; i < sig .Results ().Len (); i ++ {
605585 if i > 0 {
606586 s += ", "
607587 }
608- s += sig .Results ().At (i ).Type (). String ( )
588+ s += typestring ( sig .Results ().At (i ).Type ())
609589 }
610590 s += ")"
611591 }
612592 return s
613593}
594+
595+ // typestring returns a stable (human-readable) type string for the given type
596+ // that can be used for interface equality checks. It is almost (but not
597+ // exactly) the same as calling t.String(). The main difference is some
598+ // normalization around `byte` vs `uint8` for example.
599+ func typestring (t types.Type ) string {
600+ // See: https://github.com/golang/go/blob/master/src/go/types/typestring.go
601+ switch t := t .(type ) {
602+ case * types.Array :
603+ return "[" + strconv .FormatInt (t .Len (), 10 ) + "]" + typestring (t .Elem ())
604+ case * types.Basic :
605+ return basicTypes [t .Kind ()]
606+ case * types.Chan :
607+ switch t .Dir () {
608+ case types .SendRecv :
609+ return "chan (" + typestring (t .Elem ()) + ")"
610+ case types .SendOnly :
611+ return "chan<- (" + typestring (t .Elem ()) + ")"
612+ case types .RecvOnly :
613+ return "<-chan (" + typestring (t .Elem ()) + ")"
614+ default :
615+ panic ("unknown channel direction" )
616+ }
617+ case * types.Interface :
618+ methods := make ([]string , t .NumMethods ())
619+ for i := range methods {
620+ method := t .Method (i )
621+ methods [i ] = method .Name () + signature (method .Type ().(* types.Signature ))
622+ }
623+ return "interface{" + strings .Join (methods , ";" ) + "}"
624+ case * types.Map :
625+ return "map[" + typestring (t .Key ()) + "]" + typestring (t .Elem ())
626+ case * types.Named :
627+ return t .String ()
628+ case * types.Pointer :
629+ return "*" + typestring (t .Elem ())
630+ case * types.Signature :
631+ return "func" + signature (t )
632+ case * types.Slice :
633+ return "[]" + typestring (t .Elem ())
634+ case * types.Struct :
635+ fields := make ([]string , t .NumFields ())
636+ for i := range fields {
637+ field := t .Field (i )
638+ fields [i ] = field .Name () + " " + typestring (field .Type ())
639+ if tag := t .Tag (i ); tag != "" {
640+ fields [i ] += " " + strconv .Quote (tag )
641+ }
642+ }
643+ return "struct{" + strings .Join (fields , ";" ) + "}"
644+ default :
645+ panic ("unknown type: " + t .String ())
646+ }
647+ }
0 commit comments