From 389c05cc9c5177e7a2b69399037698d91cd4266a Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 6 Oct 2023 22:20:13 +0200 Subject: [PATCH 1/4] Avoid needlessly re-evaluating type name expressions --- Sources/FrontEnd/TypeChecking/TypeChecker.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/FrontEnd/TypeChecking/TypeChecker.swift b/Sources/FrontEnd/TypeChecking/TypeChecker.swift index d49970bdc..c9dfe0a78 100644 --- a/Sources/FrontEnd/TypeChecking/TypeChecker.swift +++ b/Sources/FrontEnd/TypeChecking/TypeChecker.swift @@ -2123,6 +2123,10 @@ struct TypeChecker { /// Evaluates and returns the value of `e`, which is a type annotation. private mutating func evalTypeAnnotation(_ e: NameExpr.ID) -> AnyType { + if let t = cache.local.exprType[e] { + return t + } + let resolution = resolve(e, withNonNominalPrefix: { (me, p) in me.evalQualification(of: p) }) switch resolution { case .done(let prefix, let suffix): From 3f6a24588d77ce9a3e1fb01805e20fb871b1b25c Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 6 Oct 2023 22:21:13 +0200 Subject: [PATCH 2/4] Rename 'MemberLookupKey' to 'TypeLookupKey' --- Sources/FrontEnd/TypeChecking/TypeChecker.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/FrontEnd/TypeChecking/TypeChecker.swift b/Sources/FrontEnd/TypeChecking/TypeChecker.swift index c9dfe0a78..a3f49c715 100644 --- a/Sources/FrontEnd/TypeChecking/TypeChecker.swift +++ b/Sources/FrontEnd/TypeChecking/TypeChecker.swift @@ -2488,7 +2488,7 @@ struct TypeChecker { break } - let key = Cache.MemberLookupKey(nominalScope, in: scopeOfUse) + let key = Cache.TypeLookupKey(nominalScope, in: scopeOfUse) if let m = cache.scopeToMembers[key]?[stem] { return m } @@ -4770,8 +4770,8 @@ struct TypeChecker { /// A lookup table. typealias LookupTable = [String: Set] - /// A key in a member lookup table. - typealias MemberLookupKey = ScopedValue + /// A key in a type lookup table. + typealias TypeLookupKey = ScopedValue /// The local instance being type checked. private(set) var local: TypedProgram @@ -4798,7 +4798,7 @@ struct TypeChecker { /// /// This map serves as cache for `lookup(_:memberOf:exposedTo)`. At no point is it guaranteed /// to be complete. - var scopeToMembers: [MemberLookupKey: LookupTable] = [:] + var scopeToMembers: [TypeLookupKey: LookupTable] = [:] /// A map from lexical scope to the names introduced in it. /// From 3cd60f03da46b67cd5066816953cfcd74e456609 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 6 Oct 2023 22:21:42 +0200 Subject: [PATCH 3/4] Add a memo cache for 'conformedTraits(of:in:)' --- .../FrontEnd/TypeChecking/TypeChecker.swift | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/Sources/FrontEnd/TypeChecking/TypeChecker.swift b/Sources/FrontEnd/TypeChecking/TypeChecker.swift index a3f49c715..54f764e97 100644 --- a/Sources/FrontEnd/TypeChecking/TypeChecker.swift +++ b/Sources/FrontEnd/TypeChecking/TypeChecker.swift @@ -123,24 +123,33 @@ struct TypeChecker { /// Returns the traits to which `t` is declared conforming in `scopeOfUse`. mutating func conformedTraits(of t: AnyType, in scopeOfUse: AnyScopeID) -> Set { + let key = Cache.TypeLookupKey(t, in: scopeOfUse) + if let r = cache.typeToConformedTraits[key] { + return r + } + + var result: Set switch t.base { case let u as BoundGenericType: - return conformedTraits(of: u.base, in: scopeOfUse) + result = conformedTraits(of: u.base, in: scopeOfUse) case let u as BuiltinType: - return conformedTraits(of: u, in: scopeOfUse) + result = conformedTraits(of: u, in: scopeOfUse) case let u as GenericTypeParameterType: - return conformedTraits(of: u, in: scopeOfUse) + result = conformedTraits(of: u, in: scopeOfUse) case let u as ProductType: - return conformedTraits(of: u, in: scopeOfUse) + result = conformedTraits(of: u, in: scopeOfUse) case let u as TraitType: - return conformedTraits(of: u, in: scopeOfUse) + result = conformedTraits(of: u, in: scopeOfUse) case let u as TypeAliasType: - return conformedTraits(of: u.resolved, in: scopeOfUse) + result = conformedTraits(of: u.resolved, in: scopeOfUse) case let u as WitnessType: - return conformedTraits(of: u, in: scopeOfUse) + result = conformedTraits(of: u, in: scopeOfUse) default: - return conformedTraits(declaredInExtensionsOf: t, exposedTo: scopeOfUse) + result = conformedTraits(declaredInExtensionsOf: t, exposedTo: scopeOfUse) } + + cache.typeToConformedTraits[key] = result + return result } /// Returns the traits to which `t` is declared conforming in `scopeOfUse`. @@ -4805,6 +4814,11 @@ struct TypeChecker { /// This map serves as cache for `names(introducedIn:)`. var scopeToNames: [AnyScopeID: LookupTable] = [:] + /// A map from type to the traits to which in conforms in a given scope. + /// + /// This map serves as cache for `conformedTraits(of:in:)`. + var typeToConformedTraits: [TypeLookupKey: Set] = [:] + /// Creates an instance for memoizing type checking results in `local` and comminicating them /// to concurrent type checkers using `shared`. init(local: TypedProgram, shared: SharedMutable? = nil) { From b2d35afb9c67e991192b402485a968fba36abcac Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 6 Oct 2023 23:04:48 +0200 Subject: [PATCH 4/4] Add a memo cache for 'extensions(of:exposedTo:)' --- Sources/FrontEnd/TypeChecking/TypeChecker.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Sources/FrontEnd/TypeChecking/TypeChecker.swift b/Sources/FrontEnd/TypeChecking/TypeChecker.swift index 54f764e97..36772460b 100644 --- a/Sources/FrontEnd/TypeChecking/TypeChecker.swift +++ b/Sources/FrontEnd/TypeChecking/TypeChecker.swift @@ -2726,6 +2726,11 @@ struct TypeChecker { private mutating func extensions( of subject: AnyType, exposedTo scopeOfUse: AnyScopeID ) -> [AnyDeclID] { + let key = Cache.TypeLookupKey(subject, in: scopeOfUse) + if let r = cache.typeToExtensions[key] { + return r + } + let subject = canonical(subject, in: scopeOfUse) var matches: [AnyDeclID] = [] var root: ModuleDecl.ID? = nil @@ -2756,6 +2761,7 @@ struct TypeChecker { reduce(decls: symbols, extending: subject, in: scopeOfUse, into: &matches) } + cache.typeToExtensions[key] = matches return matches } @@ -4819,6 +4825,11 @@ struct TypeChecker { /// This map serves as cache for `conformedTraits(of:in:)`. var typeToConformedTraits: [TypeLookupKey: Set] = [:] + /// A map from type to its extensions in a given scope. + /// + /// This map serves as cache for `extensions(of:exposedTo:)`. + var typeToExtensions: [TypeLookupKey: [AnyDeclID]] = [:] + /// Creates an instance for memoizing type checking results in `local` and comminicating them /// to concurrent type checkers using `shared`. init(local: TypedProgram, shared: SharedMutable? = nil) {