aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2/environment.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/types2/environment.go')
-rw-r--r--src/cmd/compile/internal/types2/environment.go81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/types2/environment.go b/src/cmd/compile/internal/types2/environment.go
new file mode 100644
index 0000000000..fe9a3099fe
--- /dev/null
+++ b/src/cmd/compile/internal/types2/environment.go
@@ -0,0 +1,81 @@
+// Copyright 2021 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 types2
+
+import (
+ "bytes"
+ "strings"
+ "sync"
+)
+
+// An Environment is an opaque type checking environment. It may be used to
+// share identical type instances across type-checked packages or calls to
+// Instantiate.
+//
+// It is safe for concurrent use.
+type Environment struct {
+ mu sync.Mutex
+ typeMap map[string]*Named // type hash -> instance
+ nextID int // next unique ID
+ seen map[*Named]int // assigned unique IDs
+}
+
+// NewEnvironment creates a new Environment.
+func NewEnvironment() *Environment {
+ return &Environment{
+ typeMap: make(map[string]*Named),
+ seen: make(map[*Named]int),
+ }
+}
+
+// TypeHash returns a string representation of typ, which can be used as an exact
+// type hash: types that are identical produce identical string representations.
+// If typ is a *Named type and targs is not empty, typ is printed as if it were
+// instantiated with targs. The result is guaranteed to not contain blanks (" ").
+func (env *Environment) TypeHash(typ Type, targs []Type) string {
+ assert(env != nil)
+ assert(typ != nil)
+ var buf bytes.Buffer
+
+ h := newTypeHasher(&buf, env)
+ if named, _ := typ.(*Named); named != nil && len(targs) > 0 {
+ // Don't use WriteType because we need to use the provided targs
+ // and not any targs that might already be with the *Named type.
+ h.typePrefix(named)
+ h.typeName(named.obj)
+ h.typeList(targs)
+ } else {
+ assert(targs == nil)
+ h.typ(typ)
+ }
+
+ return strings.Replace(buf.String(), " ", "#", -1) // ReplaceAll is not available in Go1.4
+}
+
+// typeForHash returns the recorded type for the type hash h, if it exists.
+// If no type exists for h and n is non-nil, n is recorded for h.
+func (env *Environment) typeForHash(h string, n *Named) *Named {
+ env.mu.Lock()
+ defer env.mu.Unlock()
+ if existing := env.typeMap[h]; existing != nil {
+ return existing
+ }
+ if n != nil {
+ env.typeMap[h] = n
+ }
+ return n
+}
+
+// idForType returns a unique ID for the pointer n.
+func (env *Environment) idForType(n *Named) int {
+ env.mu.Lock()
+ defer env.mu.Unlock()
+ id, ok := env.seen[n]
+ if !ok {
+ id = env.nextID
+ env.seen[n] = id
+ env.nextID++
+ }
+ return id
+}