github.com/bir3/gocompiler@v0.9.2202/src/go/types/context.go (about) 1 // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. 2 3 // Copyright 2021 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package types 8 9 import ( 10 "bytes" 11 "fmt" 12 "strconv" 13 "strings" 14 "sync" 15 ) 16 17 // This file contains a definition of the type-checking context; an opaque type 18 // that may be supplied by users during instantiation. 19 // 20 // Contexts serve two purposes: 21 // - reduce the duplication of identical instances 22 // - short-circuit instantiation cycles 23 // 24 // For the latter purpose, we must always have a context during instantiation, 25 // whether or not it is supplied by the user. For both purposes, it must be the 26 // case that hashing a pointer-identical type produces consistent results 27 // (somewhat obviously). 28 // 29 // However, neither of these purposes require that our hash is perfect, and so 30 // this was not an explicit design goal of the context type. In fact, due to 31 // concurrent use it is convenient not to guarantee de-duplication. 32 // 33 // Nevertheless, in the future it could be helpful to allow users to leverage 34 // contexts to canonicalize instances, and it would probably be possible to 35 // achieve such a guarantee. 36 37 // A Context is an opaque type checking context. It may be used to share 38 // identical type instances across type-checked packages or calls to 39 // Instantiate. Contexts are safe for concurrent use. 40 // 41 // The use of a shared context does not guarantee that identical instances are 42 // deduplicated in all cases. 43 type Context struct { 44 mu sync.Mutex 45 typeMap map[string][]ctxtEntry // type hash -> instances entries 46 nextID int // next unique ID 47 originIDs map[Type]int // origin type -> unique ID 48 } 49 50 type ctxtEntry struct { 51 orig Type 52 targs []Type 53 instance Type // = orig[targs] 54 } 55 56 // NewContext creates a new Context. 57 func NewContext() *Context { 58 return &Context{ 59 typeMap: make(map[string][]ctxtEntry), 60 originIDs: make(map[Type]int), 61 } 62 } 63 64 // instanceHash returns a string representation of typ instantiated with targs. 65 // The hash should be a perfect hash, though out of caution the type checker 66 // does not assume this. The result is guaranteed to not contain blanks. 67 func (ctxt *Context) instanceHash(orig Type, targs []Type) string { 68 assert(ctxt != nil) 69 assert(orig != nil) 70 var buf bytes.Buffer 71 72 h := newTypeHasher(&buf, ctxt) 73 h.string(strconv.Itoa(ctxt.getID(orig))) 74 // Because we've already written the unique origin ID this call to h.typ is 75 // unnecessary, but we leave it for hash readability. It can be removed later 76 // if performance is an issue. 77 h.typ(orig) 78 if len(targs) > 0 { 79 // TODO(rfindley): consider asserting on isGeneric(typ) here, if and when 80 // isGeneric handles *Signature types. 81 h.typeList(targs) 82 } 83 84 return strings.ReplaceAll(buf.String(), " ", "#") 85 } 86 87 // lookup returns an existing instantiation of orig with targs, if it exists. 88 // Otherwise, it returns nil. 89 func (ctxt *Context) lookup(h string, orig Type, targs []Type) Type { 90 ctxt.mu.Lock() 91 defer ctxt.mu.Unlock() 92 93 for _, e := range ctxt.typeMap[h] { 94 if identicalInstance(orig, targs, e.orig, e.targs) { 95 return e.instance 96 } 97 if debug { 98 // Panic during development to surface any imperfections in our hash. 99 panic(fmt.Sprintf("non-identical instances: (orig: %s, targs: %v) and %s", orig, targs, e.instance)) 100 } 101 } 102 103 return nil 104 } 105 106 // update de-duplicates n against previously seen types with the hash h. If an 107 // identical type is found with the type hash h, the previously seen type is 108 // returned. Otherwise, n is returned, and recorded in the Context for the hash 109 // h. 110 func (ctxt *Context) update(h string, orig Type, targs []Type, inst Type) Type { 111 assert(inst != nil) 112 113 ctxt.mu.Lock() 114 defer ctxt.mu.Unlock() 115 116 for _, e := range ctxt.typeMap[h] { 117 if inst == nil || Identical(inst, e.instance) { 118 return e.instance 119 } 120 if debug { 121 // Panic during development to surface any imperfections in our hash. 122 panic(fmt.Sprintf("%s and %s are not identical", inst, e.instance)) 123 } 124 } 125 126 ctxt.typeMap[h] = append(ctxt.typeMap[h], ctxtEntry{ 127 orig: orig, 128 targs: targs, 129 instance: inst, 130 }) 131 132 return inst 133 } 134 135 // getID returns a unique ID for the type t. 136 func (ctxt *Context) getID(t Type) int { 137 ctxt.mu.Lock() 138 defer ctxt.mu.Unlock() 139 id, ok := ctxt.originIDs[t] 140 if !ok { 141 id = ctxt.nextID 142 ctxt.originIDs[t] = id 143 ctxt.nextID++ 144 } 145 return id 146 }