From 9c3077d4ab14e0089a06c68e2f73add8c2353c2a Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Mon, 9 Sep 2024 11:53:04 +0200 Subject: [PATCH] Add an option to log requirement systems after completion --- Sources/Driver/Driver.swift | 23 +++++++++++-- .../FrontEnd/TypeChecking/TypeChecker.swift | 32 +++++++++++++++---- Sources/FrontEnd/TypedProgram.swift | 24 ++++++++++---- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/Sources/Driver/Driver.swift b/Sources/Driver/Driver.swift index 5e123f79a..0d8ccccca 100644 --- a/Sources/Driver/Driver.swift +++ b/Sources/Driver/Driver.swift @@ -102,6 +102,13 @@ public struct Driver: ParsableCommand { valueName: "file:line")) private var inferenceTracingSite: SourceLine? + @Option( + name: [.customLong("show-requirements")], + help: ArgumentHelp( + "Log the requirement system of the generic declaration at the given line.", + valueName: "file:line")) + private var showRequirementsSite: SourceLine? + @Option( name: [.customLong("emit")], help: ArgumentHelp( @@ -258,11 +265,14 @@ public struct Driver: ParsableCommand { dependencies = try TypedProgram( annotating: ScopedProgram(a), inParallel: experimentalParallelTypeChecking, reportingDiagnosticsTo: &log, - tracingInferenceIf: shouldTraceInference) + tracingInferenceIf: shouldTraceInference, + loggingRequirementSystemIf: shouldLogRequirements) } let (program, sourceModule) = try dependencies.loadModule( - reportingDiagnosticsTo: &log, tracingInferenceIf: shouldTraceInference + reportingDiagnosticsTo: &log, + tracingInferenceIf: shouldTraceInference, + loggingRequirementSystemIf: shouldLogRequirements ) { (ast, log, space) in try ast.loadModule( productName, parsing: sourceFiles(in: inputs), inNodeSpace: space, @@ -355,6 +365,15 @@ public struct Driver: ParsableCommand { } } + /// Returns `true` if the requirement system of `n`, which is in `p`, should be logged. + private func shouldLogRequirements(_ n: AnyDeclID, _ p: TypedProgram) -> Bool { + if let s = showRequirementsSite { + return (n.kind.value is GenericDecl.Type) && s.bounds.contains(p[n].site.start) + } else { + return false + } + } + /// Returns `program` lowered to Hylo IR, accumulating diagnostics in `log` and throwing if an /// error occurred. /// diff --git a/Sources/FrontEnd/TypeChecking/TypeChecker.swift b/Sources/FrontEnd/TypeChecking/TypeChecker.swift index 067855630..934bc100f 100644 --- a/Sources/FrontEnd/TypeChecking/TypeChecker.swift +++ b/Sources/FrontEnd/TypeChecking/TypeChecker.swift @@ -20,10 +20,14 @@ struct TypeChecker { /// The representation under construction. private var cache: Cache - /// A closure that takes a node and its containing program, and returns `true` if a trace of type - /// inference should be logged on the console for that node. + /// A closure that accepts a node with its containing program and returns `true` if a trace of + /// type inference should be logged on the console for that node. private let shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)? + /// A closure that accepts a generic declaration with its containing program and returns `true` + /// if the requirement system of its environment should be logged on the console. + private let shouldLogRequirementSystem: ((AnyDeclID, TypedProgram) -> Bool)? + /// The local copy of the program being type checked. var program: TypedProgram { cache.local @@ -34,16 +38,19 @@ struct TypeChecker { self.identifier = 0 self.cache = Cache(local: p) self.shouldTraceInference = nil + self.shouldLogRequirementSystem = nil } /// Creates an instance for constructing `instanceUnderConstruction`. init( constructing instanceUnderConstruction: TypedProgram, - tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)? + tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)?, + loggingRequirementSystemIf shouldLogRequirements: ((AnyDeclID, TypedProgram) -> Bool)? ) { self.identifier = 0 self.cache = Cache(local: instanceUnderConstruction) self.shouldTraceInference = shouldTraceInference + self.shouldLogRequirementSystem = shouldLogRequirements } /// Creates an instance with given `identifier` for constructing `instanceUnderConstruction` @@ -53,13 +60,15 @@ struct TypeChecker { init( _ identifier: UInt8, collaborativelyConstructing instanceUnderConstruction: SharedMutable, - tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)? + tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)?, + loggingRequirementSystemIf shouldLogRequirements: ((AnyDeclID, TypedProgram) -> Bool)? ) { self.identifier = identifier self.nextFreshVariableIdentifier = UInt64(identifier) << 56 self.cache = instanceUnderConstruction.read( applying: { Cache(local: $0, shared: instanceUnderConstruction) }) self.shouldTraceInference = shouldTraceInference + self.shouldLogRequirementSystem = shouldLogRequirements } /// Reports the given diagnostic. @@ -1429,21 +1438,30 @@ struct TypeChecker { /// Builds and type checks the generic environment of `d`. private mutating func checkEnvironment(of d: T.ID) { // TODO: Type check default values - _ = environment(of: d) + let e = environment(of: d) check(program[d].genericParameters) + if let f = shouldLogRequirementSystem, f(AnyDeclID(d), program) { + print(program.describe(e.requirements)) + } } /// Builds and type checks the generic environment of `d`. private mutating func checkEnvironment(of d: TraitDecl.ID) { // TODO: Type check default values - _ = environment(of: d) + let e = environment(of: d) check(program[d].genericParameters) + if let f = shouldLogRequirementSystem, f(AnyDeclID(d), program) { + print(program.describe(e.requirements)) + } } /// Builds and type checks the generic environment of `d`. private mutating func checkEnvironment(of d: T.ID) { // TODO: Type check default values - _ = environment(of: d) + let e = environment(of: d) + if let f = shouldLogRequirementSystem, f(AnyDeclID(d), program) { + print(program.describe(e.requirements)) + } } /// Type checks the conformances declared by `d`. diff --git a/Sources/FrontEnd/TypedProgram.swift b/Sources/FrontEnd/TypedProgram.swift index dc223bd91..840c6fc2e 100644 --- a/Sources/FrontEnd/TypedProgram.swift +++ b/Sources/FrontEnd/TypedProgram.swift @@ -63,7 +63,8 @@ public struct TypedProgram { annotating base: ScopedProgram, inParallel typeCheckingIsParallel: Bool = false, reportingDiagnosticsTo log: inout DiagnosticSet, - tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)? = nil + tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)? = nil, + loggingRequirementSystemIf shouldLogRequirements: ((AnyDeclID, TypedProgram) -> Bool)? = nil ) throws { let instanceUnderConstruction = SharedMutable(TypedProgram(partiallyFormedFrom: base)) @@ -75,7 +76,8 @@ public struct TypedProgram { let t = TypeCheckTask( Array(chunk), withCheckerIdentifiedBy: UInt8(i), collaborativelyConstructing: instanceUnderConstruction, - tracingInferenceIf: nil) + tracingInferenceIf: nil, + loggingRequirementSystemIf: nil) tasks.append(t) } @@ -89,7 +91,8 @@ public struct TypedProgram { self = try instanceUnderConstruction.read { var checker = TypeChecker( constructing: $0, - tracingInferenceIf: typeCheckingIsParallel ? nil : shouldTraceInference) + tracingInferenceIf: typeCheckingIsParallel ? nil : shouldTraceInference, + loggingRequirementSystemIf: typeCheckingIsParallel ? nil : shouldLogRequirements) checker.checkAllDeclarations() log.formUnion(checker.diagnostics) @@ -107,13 +110,17 @@ public struct TypedProgram { public func loadModule( reportingDiagnosticsTo log: inout DiagnosticSet, tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)? = nil, + loggingRequirementSystemIf shouldLogRequirements: ((AnyDeclID, TypedProgram) -> Bool)? = nil, creatingContentsWith make: AST.ModuleLoader ) throws -> (Self, ModuleDecl.ID) { let (p, m) = try base.loadModule(reportingDiagnosticsTo: &log, creatingContentsWith: make) var extended = self extended.base = consume p - var checker = TypeChecker(constructing: extended, tracingInferenceIf: shouldTraceInference) + var checker = TypeChecker( + constructing: extended, + tracingInferenceIf: shouldTraceInference, + loggingRequirementSystemIf: shouldLogRequirements) checker.checkModule(m) log.formUnion(checker.diagnostics) @@ -136,12 +143,15 @@ public struct TypedProgram { _ sources: [TranslationUnit.ID], withCheckerIdentifiedBy checkerIdentifier: UInt8, collaborativelyConstructing instanceUnderConstruction: SharedMutable, - tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)? + tracingInferenceIf shouldTraceInference: ((AnyNodeID, TypedProgram) -> Bool)?, + loggingRequirementSystemIf shouldLogRequirements: ((AnyDeclID, TypedProgram) -> Bool)? ) { self.sources = sources self.checker = TypeChecker( - checkerIdentifier, collaborativelyConstructing: instanceUnderConstruction, - tracingInferenceIf: shouldTraceInference) + checkerIdentifier, + collaborativelyConstructing: instanceUnderConstruction, + tracingInferenceIf: shouldTraceInference, + loggingRequirementSystemIf: shouldLogRequirements) } /// Executes the operation.