@@ -856,6 +856,8 @@ type Checker struct {
856
856
skipDirectInferenceNodes collections.Set[*ast.Node]
857
857
ctx context.Context
858
858
packagesMap map[string]bool
859
+ activeMappers []*TypeMapper
860
+ activeTypeMappersCaches []map[string]*Type
859
861
}
860
862
861
863
func NewChecker(program Program) *Checker {
@@ -21178,14 +21180,66 @@ func (c *Checker) instantiateTypeWithAlias(t *Type, m *TypeMapper, alias *TypeAl
21178
21180
c.error(c.currentNode, diagnostics.Type_instantiation_is_excessively_deep_and_possibly_infinite)
21179
21181
return c.errorType
21180
21182
}
21183
+ index := c.findActiveMapper(m)
21184
+ if index == -1 {
21185
+ c.pushActiveMapper(m)
21186
+ }
21187
+ var b KeyBuilder
21188
+ b.WriteType(t)
21189
+ b.WriteAlias(alias)
21190
+ key := b.String()
21191
+ cache := c.activeTypeMappersCaches[core.IfElse(index != -1, index, len(c.activeTypeMappersCaches)-1)]
21192
+ if cachedType, ok := cache[key]; ok {
21193
+ return cachedType
21194
+ }
21181
21195
c.TotalInstantiationCount++
21182
21196
c.instantiationCount++
21183
21197
c.instantiationDepth++
21184
21198
result := c.instantiateTypeWorker(t, m, alias)
21199
+ if index == -1 {
21200
+ c.popActiveMapper()
21201
+ } else {
21202
+ cache[key] = result
21203
+ }
21185
21204
c.instantiationDepth--
21186
21205
return result
21187
21206
}
21188
21207
21208
+ func (c *Checker) pushActiveMapper(mapper *TypeMapper) {
21209
+ c.activeMappers = append(c.activeMappers, mapper)
21210
+
21211
+ lastIndex := len(c.activeTypeMappersCaches)
21212
+ if cap(c.activeTypeMappersCaches) > lastIndex {
21213
+ // The cap may contain an empty map from popActiveMapper; reuse it.
21214
+ c.activeTypeMappersCaches = c.activeTypeMappersCaches[:lastIndex+1]
21215
+ if c.activeTypeMappersCaches[lastIndex] == nil {
21216
+ c.activeTypeMappersCaches[lastIndex] = make(map[string]*Type, 1)
21217
+ }
21218
+ } else {
21219
+ c.activeTypeMappersCaches = append(c.activeTypeMappersCaches, make(map[string]*Type, 1))
21220
+ }
21221
+ }
21222
+
21223
+ func (c *Checker) popActiveMapper() {
21224
+ c.activeMappers[len(c.activeMappers)-1] = nil
21225
+ c.activeMappers = c.activeMappers[:len(c.activeMappers)-1]
21226
+
21227
+ // Clear the map, but leave it in the list for later reuse.
21228
+ lastIndex := len(c.activeTypeMappersCaches) - 1
21229
+ clear(c.activeTypeMappersCaches[lastIndex])
21230
+ c.activeTypeMappersCaches = c.activeTypeMappersCaches[:lastIndex]
21231
+ }
21232
+
21233
+ func (c *Checker) findActiveMapper(mapper *TypeMapper) int {
21234
+ return core.FindLastIndex(c.activeMappers, func(m *TypeMapper) bool { return m == mapper })
21235
+ }
21236
+
21237
+ func (c *Checker) clearActiveMapperCaches() {
21238
+ for _, cache := range c.activeTypeMappersCaches {
21239
+ clear(cache)
21240
+ }
21241
+ }
21242
+
21189
21243
// Return true if the given type could possibly reference a type parameter for which
21190
21244
// we perform type inference (i.e. a type parameter of a generic function). We cache
21191
21245
// results for union and intersection types for performance reasons.
0 commit comments