diff options
Diffstat (limited to 'src/cmd/compile/internal/types/fmt.go')
-rw-r--r-- | src/cmd/compile/internal/types/fmt.go | 95 |
1 files changed, 65 insertions, 30 deletions
diff --git a/src/cmd/compile/internal/types/fmt.go b/src/cmd/compile/internal/types/fmt.go index 8b988952a7..0824f6d093 100644 --- a/src/cmd/compile/internal/types/fmt.go +++ b/src/cmd/compile/internal/types/fmt.go @@ -239,17 +239,37 @@ func (t *Type) String() string { return tconv(t, 0, fmtGo) } -// ShortString generates a short description of t. -// It is used in autogenerated method names, reflection, -// and itab names. -func (t *Type) ShortString() string { +// LinkString returns an unexpanded string description of t, suitable +// for use in link symbols. "Unexpanded" here means that the +// description uses `"".` to qualify identifiers from the current +// package, and "expansion" refers to the renaming step performed by +// the linker to replace these qualifiers with proper `path/to/pkg.` +// qualifiers. +// +// After expansion, the description corresponds to type identity. That +// is, for any pair of types t1 and t2, Identical(t1, t2) and +// expand(t1.LinkString()) == expand(t2.LinkString()) report the same +// value. +// +// Within a single compilation unit, LinkString always returns the +// same unexpanded description for identical types. Thus it's safe to +// use as a map key to implement a type-identity-keyed map. However, +// make sure all LinkString calls used for this purpose happen within +// the same compile process; the string keys are not stable across +// multiple processes. +func (t *Type) LinkString() string { return tconv(t, 0, fmtTypeID) } -// LongString generates a complete description of t. -// It is useful for reflection, -// or when a unique fingerprint or hash of a type is required. -func (t *Type) LongString() string { +// NameString generates a user-readable, mostly unique string +// description of t. NameString always returns the same description +// for identical types, even across compilation units. +// +// NameString qualifies identifiers by package name, so it has +// collisions when different packages share the same names and +// identifiers. It also does not distinguish function-scope defined +// types from package-scoped defined types or from each other. +func (t *Type) NameString() string { return tconv(t, 0, fmtTypeIDName) } @@ -316,31 +336,34 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type // Unless the 'L' flag was specified, if the type has a name, just print that name. if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] { - switch mode { - case fmtTypeID, fmtTypeIDName: - if verb == 'S' { - if t.Vargen != 0 { - sconv2(b, t.Sym(), 'S', mode) - fmt.Fprintf(b, "·%d", t.Vargen) - return - } - sconv2(b, t.Sym(), 'S', mode) - return - } + // Default to 'v' if verb is invalid. + if verb != 'S' { + verb = 'v' + } - if mode == fmtTypeIDName { - sconv2(b, t.Sym(), 'v', fmtTypeIDName) - return + // In unified IR, function-scope defined types will have a ·N + // suffix embedded directly in their Name. Trim this off for + // non-fmtTypeID modes. + sym := t.Sym() + if mode != fmtTypeID { + i := len(sym.Name) + for i > 0 && sym.Name[i-1] >= '0' && sym.Name[i-1] <= '9' { + i-- } - - if t.Sym().Pkg == LocalPkg && t.Vargen != 0 { - sconv2(b, t.Sym(), 'v', mode) - fmt.Fprintf(b, "·%d", t.Vargen) - return + const dot = "·" + if i >= len(dot) && sym.Name[i-len(dot):i] == dot { + sym = &Sym{Pkg: sym.Pkg, Name: sym.Name[:i-len(dot)]} } } - - sconv2(b, t.Sym(), 'v', mode) + sconv2(b, sym, verb, mode) + + // TODO(mdempsky): Investigate including Vargen in fmtTypeIDName + // output too. It seems like it should, but that mode is currently + // used in string representation used by reflection, which is + // user-visible and doesn't expect this. + if mode == fmtTypeID && t.Vargen != 0 { + fmt.Fprintf(b, "·%d", t.Vargen) + } return } @@ -567,6 +590,18 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type b.WriteString(fmt.Sprintf("%p", t)) } + case TUNION: + for i := 0; i < t.NumTerms(); i++ { + if i > 0 { + b.WriteString("|") + } + elem, tilde := t.Term(i) + if tilde { + b.WriteString("~") + } + tconv2(b, elem, 0, mode, visited) + } + case Txxx: b.WriteString("Txxx") @@ -671,7 +706,7 @@ func FmtConst(v constant.Value, sharp bool) string { // TypeHash computes a hash value for type t to use in type switch statements. func TypeHash(t *Type) uint32 { - p := t.LongString() + p := t.NameString() // Using MD5 is overkill, but reduces accidental collisions. h := md5.Sum([]byte(p)) |