From 6f5982c6d3c8e1a4abcdb8e13947e30ae4b79454 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Wed, 28 Aug 2024 21:37:06 +0200 Subject: [PATCH 1/9] Remove dead code --- Sources/IR/Mangling/Mangler.swift | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Sources/IR/Mangling/Mangler.swift b/Sources/IR/Mangling/Mangler.swift index 7e7e3ae2d..ce88fd101 100644 --- a/Sources/IR/Mangling/Mangler.swift +++ b/Sources/IR/Mangling/Mangler.swift @@ -391,19 +391,6 @@ struct Mangler { } } - /// Writes the mangled representation of `r` to `output`. - mutating func mangle(reference r: DeclReference, to output: inout Output) { - switch r { - case .direct(let d, let z): - write(operator: .directDeclReference, to: &output) - mangle(decl: d, to: &output) - write(specialization: z, to: &output) - - default: - UNIMPLEMENTED() - } - } - /// Writes the mangled representation of `symbol` to `output`. mutating func mangle(table symbol: WitnessTable, to output: inout Output) { write(operator: .witnessTable, to: &output) From 19f48dc655d4f7b6bc35cd89f510f8af4a5b25f2 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Wed, 28 Aug 2024 22:40:45 +0200 Subject: [PATCH 2/9] Ensure that function IDs are canonical --- .../FrontEnd/AST/Decl/SynthesizedFunctionDecl.swift | 1 + .../FrontEnd/CompileTimeValues/CompileTimeValue.swift | 5 +++++ Sources/FrontEnd/TypedProgram.swift | 10 ++++++++++ Sources/IR/Analysis/Module+Depolymorphize.swift | 3 ++- Sources/IR/Emitter.swift | 2 +- Sources/IR/FunctionID.swift | 6 ++++-- 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Sources/FrontEnd/AST/Decl/SynthesizedFunctionDecl.swift b/Sources/FrontEnd/AST/Decl/SynthesizedFunctionDecl.swift index 495aa313d..d28721a5e 100644 --- a/Sources/FrontEnd/AST/Decl/SynthesizedFunctionDecl.swift +++ b/Sources/FrontEnd/AST/Decl/SynthesizedFunctionDecl.swift @@ -50,6 +50,7 @@ public struct SynthesizedFunctionDecl: Hashable { parameterizedBy genericParameters: [GenericParameterDecl.ID], in scope: AnyScopeID ) { + precondition(type[.isCanonical]) precondition(type.environment.base is TupleType) self.type = type self.genericParameters = genericParameters diff --git a/Sources/FrontEnd/CompileTimeValues/CompileTimeValue.swift b/Sources/FrontEnd/CompileTimeValues/CompileTimeValue.swift index 3999ee4d4..e7a71ffa1 100644 --- a/Sources/FrontEnd/CompileTimeValues/CompileTimeValue.swift +++ b/Sources/FrontEnd/CompileTimeValues/CompileTimeValue.swift @@ -16,6 +16,11 @@ public enum CompileTimeValue: Hashable { } } + /// `true` iff self is in canonical form. + public var isCanonical: Bool { + if let t = asType { t[.isCanonical] } else { true } + } + /// `true` if `self` is a `TypeVariable`. public var isTypeVariable: Bool { asType?.base is TypeVariable diff --git a/Sources/FrontEnd/TypedProgram.swift b/Sources/FrontEnd/TypedProgram.swift index 3c7e84a04..1a51addf8 100644 --- a/Sources/FrontEnd/TypedProgram.swift +++ b/Sources/FrontEnd/TypedProgram.swift @@ -162,6 +162,16 @@ public struct TypedProgram { self.base = base } + /// Returns the canonical form of `d`'s type. + public func canonical(typeOf d: T) -> AnyType { + canonical(declType[d]!, in: nodeToScope[d]!) + } + + /// Returns the canonical form of `e`'s type. + public func canonical(typeOf e: T) -> AnyType { + canonical(exprType[e]!, in: nodeToScope[e]!) + } + /// Returns the canonical form of `t` in `scopeOfUse`. public func canonical(_ t: AnyType, in scopeOfUse: AnyScopeID) -> AnyType { if t[.isCanonical] { return t } diff --git a/Sources/IR/Analysis/Module+Depolymorphize.swift b/Sources/IR/Analysis/Module+Depolymorphize.swift index 4e8539c9a..cd6e7fe17 100644 --- a/Sources/IR/Analysis/Module+Depolymorphize.swift +++ b/Sources/IR/Analysis/Module+Depolymorphize.swift @@ -79,7 +79,8 @@ extension IR.Program { // TODO: Use existentialization unless the subscript is inlinable - let g = monomorphize(s.callee, for: s.specialization, usedIn: modules[m]!.scope(containing: i)) + let z = base.canonical(s.specialization, in: modules[m]!.scope(containing: i)) + let g = monomorphize(s.callee, for: z, usedIn: modules[m]!.scope(containing: i)) let new = modules[m]!.makeProject( s.projection, applying: g, specializedBy: .empty, to: s.operands, at: s.site) modules[m]!.replace(i, with: new) diff --git a/Sources/IR/Emitter.swift b/Sources/IR/Emitter.swift index 3c6fcf102..eda0e4955 100644 --- a/Sources/IR/Emitter.swift +++ b/Sources/IR/Emitter.swift @@ -494,7 +494,7 @@ struct Emitter { precondition(program.isGlobal(d)) precondition(read(program[d].pattern.introducer.value, { ($0 == .let) || ($0 == .sinklet) })) - let r = RemoteType(.set, program[d].type) + let r = RemoteType(.set, program.canonical(typeOf: d)) let l = ArrowType( receiverEffect: .set, environment: ^TupleType(types: [^r]), inputs: [], output: .void) let f = SynthesizedFunctionDecl( diff --git a/Sources/IR/FunctionID.swift b/Sources/IR/FunctionID.swift index e89b0dae6..9c0a2f846 100644 --- a/Sources/IR/FunctionID.swift +++ b/Sources/IR/FunctionID.swift @@ -39,19 +39,21 @@ extension Function { /// Creates the identity of the lowered form of `s`. init(_ s: SynthesizedFunctionDecl) { + precondition(s.type[.isCanonical]) self.value = .synthesized(s) } /// Creates the identity of the existentialized form of `base`. - public init(existentialized base: Function.ID) { + init(existentialized base: Function.ID) { self.value = .existentialized(base: base) } /// Creates the identity of the monomorphized form of `base` for `arguments`. /// /// - Requires: `arguments` is not empty. - public init(monomorphized base: Function.ID, for arguments: GenericArguments) { + init(monomorphized base: Function.ID, for arguments: GenericArguments) { precondition(!arguments.isEmpty) + precondition(arguments.allSatisfy(\.value.isCanonical)) self.value = .monomorphized(base: base, arguments: arguments) } From 2b556625ff1fa23882bab5408cea996e8c45c52a Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Wed, 28 Aug 2024 22:43:03 +0200 Subject: [PATCH 3/9] Refactor the mangling algorithm --- Sources/IR/Mangling/Demangler.swift | 4 + Sources/IR/Mangling/Mangler.swift | 818 +++++++++--------- Sources/IR/Mangling/ManglingOperator.swift | 4 + .../IR/Mangling/TypedProgram+Mangling.swift | 19 +- 4 files changed, 447 insertions(+), 398 deletions(-) diff --git a/Sources/IR/Mangling/Demangler.swift b/Sources/IR/Mangling/Demangler.swift index fd894e45c..7fed511fe 100644 --- a/Sources/IR/Mangling/Demangler.swift +++ b/Sources/IR/Mangling/Demangler.swift @@ -110,6 +110,10 @@ struct Demangler { case .varDecl: demangled = take(VarDecl.self, qualifiedBy: qualification, from: &stream) + case .lookupRelative: + fatalError() + case .bindingDecl: + fatalError() case .subscriptImplType: fatalError() diff --git a/Sources/IR/Mangling/Mangler.swift b/Sources/IR/Mangling/Mangler.swift index ce88fd101..85bd45713 100644 --- a/Sources/IR/Mangling/Mangler.swift +++ b/Sources/IR/Mangling/Mangler.swift @@ -21,691 +21,735 @@ struct Mangler { /// The program defining the symbols being defined. private let program: TypedProgram - /// The scope in which names are mangled. - private let scopeOfUse: AnyScopeID - /// A table mapping mangled symbols to their position in the symbol lookup table. - private var symbolID: [Symbol: Int] = [:] + private var symbolPosition: [Symbol: Int] = [:] - /// The ID of the next symbol inserted in the symbol lookup table. - private var nextSymbolID = 0 + /// The innermost scope being mangled, if any. + private var qualification: AnyScopeID? /// A table mapping known symbols to their reserved mangled identifier. - private var reserved: [Symbol: ReservedSymbol] = [ - .type(.any): .any, - .type(.void): .void, - .type(.never): .never, - ] - - /// Creates an instance mangling symbols defined in `programs` in `scopeOfUse`. - init(_ program: TypedProgram, in scopeOfUse: AnyScopeID) { + private var reserved: [Symbol: ReservedSymbol] = [:] + + /// Creates an instance mangling symbols defined in `programs`. + init(_ program: TypedProgram) { self.program = program - self.scopeOfUse = scopeOfUse + initializeReservedSymbols() + } + /// Initializes the table of reserved symbols. + private mutating func initializeReservedSymbols() { + reserved[.type(.any)] = .any + reserved[.type(.never)] = .never + reserved[.type(.void)] = .void if program.ast.coreModuleIsLoaded { - self.reserved[.node(AnyNodeID(program.ast.coreLibrary!))] = .hylo - register(coreType: "Bool", as: .bool) - register(coreType: "Int", as: .int) - register(coreType: "Float64", as: .float64) - register(coreType: "String", as: .string) + reserved[.node(AnyNodeID(program.ast.coreLibrary!))] = .hylo + registerReservedCoreType("Bool", as: .bool) + registerReservedCoreType("Int", as: .int) + registerReservedCoreType("Float64", as: .float64) + registerReservedCoreType("String", as: .string) } } - /// Associates `coreType` to `r`. - private mutating func register(coreType: String, as r: ReservedSymbol) { - let d = AnyNodeID(program.ast.coreType(coreType)!.decl) - reserved[.node(d)] = r + /// Extends `self.reserved` to associate the core type named `n` to the reserved symbol `s`. + private mutating func registerReservedCoreType(_ n: String, as s: ReservedSymbol) { + reserved[.node(AnyNodeID(program.ast.coreType(n)!.decl))] = s } - /// Writes the mangled representation of `d` to `output`. - mutating func mangle(decl d: T, to output: inout Output) { - if let m = ModuleDecl.ID(d) { - write(scope: AnyScopeID(m), to: &output) - return - } + /// Returns the mangled representation of `s`. + mutating func mangled(type s: AnyType) -> Output { + mangled(s, manglingWith: { (me, s, o) in me.append(type: s, to: &o) }) + } - if writeLookup(.node(AnyNodeID(d)), to: &output) { - return + /// Returns the mangled representation of `s`. + mutating func mangled(decl s: T) -> Output { + mangled(s, manglingWith: { (me, s, o) in me.append(decl: s, to: &o) }) + } + + /// Returns the mangled representation of `s` + mutating func mangled(function s: Function.ID) -> Output { + mangled(s, manglingWith: { (me, s, o) in me.append(function: s, to: &o) }) + } + + /// Returns the mangled representation of `s` + mutating func mangled(table s: WitnessTable) -> Output { + mangled(s, manglingWith: { (me, s, o) in me.append(table: s, to: &o) }) + } + + /// Returns the mangled representation of `s`, calling `mangle` to compute it. + private mutating func mangled( + _ s: T, manglingWith mangle: (inout Self, T, inout Output) -> Void + ) -> Output { + var p = symbolPosition + var q = qualification + defer { + swap(&p, &symbolPosition) + swap(&q, &qualification) } - writeQualification(of: d, to: &output) + var output = "" + mangle(&self, s, &output) + return output + } + + /// Writes the mangled representation of `d` to `output`. + private mutating func append(decl d: T, to output: inout Output) { + let s = Symbol.node(.init(d)) + if appendIf(reservedOrRecorded: s, to: &output) { return } + appendQualification(of: d, to: &output) if let s = AnyScopeID(d) { - write(scope: s, to: &output) + append(scope: s, to: &output) return } switch d.kind { case AssociatedTypeDecl.self: - write(entity: AssociatedTypeDecl.ID(d)!, to: &output) + append(entity: AssociatedTypeDecl.ID(d)!, to: &output) case AssociatedValueDecl.self: - write(entity: AssociatedValueDecl.ID(d)!, to: &output) + append(entity: AssociatedValueDecl.ID(d)!, to: &output) case BindingDecl.self: - write(entity: BindingDecl.ID(d)!, to: &output) + append(entity: BindingDecl.ID(d)!, to: &output) case ImportDecl.self: - write(entity: ImportDecl.ID(d)!, to: &output) + append(entity: ImportDecl.ID(d)!, to: &output) case GenericParameterDecl.self: - write(entity: GenericParameterDecl.ID(d)!, to: &output) + append(entity: GenericParameterDecl.ID(d)!, to: &output) case ParameterDecl.self: - write(entity: ParameterDecl.ID(d)!, to: &output) + append(entity: ParameterDecl.ID(d)!, to: &output) case VarDecl.self: - write(entity: VarDecl.ID(d)!, to: &output) + append(entity: VarDecl.ID(d)!, to: &output) default: unexpected(d, in: program.ast) } - symbolID[.node(AnyNodeID(d))] = nextSymbolID - nextSymbolID += 1 + symbolPosition[.node(AnyNodeID(d))] = symbolPosition.count + } + + /// Writes the mangled representation of `d` to `output`. + private mutating func append(entity d: T.ID, to output: inout Output) { + append(operator: .init(for: T.self), to: &output) + append(string: program.ast[d].baseName, to: &output) } /// Writes the mangled representation of `d` to `output`. - private mutating func write(entity d: BindingDecl.ID, to output: inout Output) { - let n = program.ast.names(in: program[d].pattern).first! - let v = program.ast[n.pattern].decl - mangle(decl: v, to: &output) + private mutating func append(entity d: BindingDecl.ID, to output: inout Output) { + append(operator: .bindingDecl, to: &output) + append(items: program.ast.names(in: program[d].pattern), to: &output) { (me, n, o) in + me.append(decl: me.program.ast[n.pattern].decl, to: &o) + } } /// Writes the mangled qualification of `n` to `output`. - private mutating func writeQualification(of n: T, to output: inout Output) { - var qualification: [AnyScopeID] = [] + private mutating func appendQualification(of n: T, to output: inout Output) { + // Modules have no qualification. + if n.kind == ModuleDecl.self { return } + + // Find the prefix of the qualification that should be mangled as a reference. + var qs: [AnyScopeID] = [] for s in program.scopes(from: program[n].scope) { - if writeLookup(.node(AnyNodeID(s)), to: &output) { + // Anonymous scopes corresponding to the body of a function aren't mangled. + if let d = BraceStmt.ID(s), program.isCallableBody(d) { + continue + } else if appendIf(reservedOrRecorded: .node(.init(s)), to: &output) { + break + } else if s == qualification { + append(operator: .lookupRelative, to: &output) break } else { - qualification.append(s) + qs.append(s) } } - for s in qualification.reversed() { - // Anonymous scopes corresponding to the body of a function aren't mangled. - if let p = BraceStmt.ID(s), program.isCallableBody(p) { - continue - } - write(scope: s, to: &output) + // Write the mangled representation of the qualification's suffix. + for s in qs.reversed() { + append(scope: s, to: &output) } } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(scope symbol: AnyScopeID, to output: inout Output) { - if writeLookup(.node(AnyNodeID(symbol)), to: &output) { - return - } + /// Writes the mangled representation of `s` to `output`. + private mutating func append(scope s: AnyScopeID, to output: inout Output) { + let n = Symbol.node(.init(s)) + if appendIf(reservedOrRecorded: n, to: &output) { return } - symbolID[.node(AnyNodeID(symbol))] = nextSymbolID - nextSymbolID += 1 - - switch symbol.kind { + let q = qualification + qualification = s + switch s.kind { case BraceStmt.self: - write(anonymousScope: symbol, to: &output) + append(anonymous: s, to: &output) case ConditionalExpr.self: - write(anonymousScope: symbol, to: &output) + append(anonymous: s, to: &output) case ConditionalStmt.self: - write(anonymousScope: symbol, to: &output) + append(anonymous: s, to: &output) case ConformanceDecl.self: - write(conformance: ConformanceDecl.ID(symbol)!, to: &output) + append(conformance: ConformanceDecl.ID(s)!, to: &output) case ExtensionDecl.self: - write(extension: ExtensionDecl.ID(symbol)!, to: &output) + append(extension: ExtensionDecl.ID(s)!, to: &output) case ForStmt.self: - write(anonymousScope: symbol, to: &output) + append(anonymous: s, to: &output) case FunctionDecl.self: - write(function: FunctionDecl.ID(symbol)!, to: &output) + append(function: FunctionDecl.ID(s)!, to: &output) case InitializerDecl.self: - write(initializer: InitializerDecl.ID(symbol)!, to: &output) + append(initializer: InitializerDecl.ID(s)!, to: &output) case MatchCase.self: - write(anonymousScope: symbol, to: &output) + append(anonymous: s, to: &output) case MethodDecl.self: - write(methodDecl: MethodDecl.ID(symbol)!, to: &output) + append(methodDecl: MethodDecl.ID(s)!, to: &output) case MethodImpl.self: - write(methodImpl: MethodImpl.ID(symbol)!, to: &output) + append(methodImpl: MethodImpl.ID(s)!, to: &output) case ModuleDecl.self: - write(entity: ModuleDecl.ID(symbol)!, to: &output) + append(entity: ModuleDecl.ID(s)!, to: &output) case NamespaceDecl.self: - write(entity: NamespaceDecl.ID(symbol)!, to: &output) + append(entity: NamespaceDecl.ID(s)!, to: &output) case ProductTypeDecl.self: - write(entity: ProductTypeDecl.ID(symbol)!, to: &output) + append(entity: ProductTypeDecl.ID(s)!, to: &output) case SubscriptDecl.self: - write(subscriptDecl: SubscriptDecl.ID(symbol)!, to: &output) + append(subscriptDecl: SubscriptDecl.ID(s)!, to: &output) case SubscriptImpl.self: - write(subscriptImpl: SubscriptImpl.ID(symbol)!, to: &output) + append(subscriptImpl: SubscriptImpl.ID(s)!, to: &output) case TraitDecl.self: - write(entity: TraitDecl.ID(symbol)!, to: &output) + append(entity: TraitDecl.ID(s)!, to: &output) case TranslationUnit.self: - write(translationUnit: TranslationUnit.ID(symbol)!, to: &output) + append(translationUnit: TranslationUnit.ID(s)!, to: &output) case TypeAliasDecl.self: - write(entity: TypeAliasDecl.ID(symbol)!, to: &output) + append(entity: TypeAliasDecl.ID(s)!, to: &output) case WhileStmt.self: - write(anonymousScope: symbol, to: &output) + append(anonymous: s, to: &output) default: - unexpected(symbol, in: program.ast) + unexpected(s, in: program.ast) } + qualification = q + symbolPosition[n] = symbolPosition.count } /// Writes the mangled representation of `d` to `output`. - private mutating func write(entity d: T.ID, to output: inout Output) { - write(operator: .init(for: T.self), to: &output) - write(string: program.ast[d].baseName, to: &output) - } - - /// Writes the mangled representation of `d` to `output`. - private mutating func write(anonymousScope d: AnyScopeID, to output: inout Output) { - write(operator: .anonymousScope, to: &output) - write(integer: Int(d.rawValue.bits), to: &output) + private mutating func append(anonymous d: AnyScopeID, to output: inout Output) { + append(operator: .anonymousScope, to: &output) + append(integer: Int(d.rawValue.bits), to: &output) } /// Writes the mangled representation of `d` to `output`. - private mutating func write(conformance d: ConformanceDecl.ID, to output: inout Output) { - write(operator: .conformanceDecl, to: &output) - mangle(type: program[d].type, to: &output) + private mutating func append(conformance d: ConformanceDecl.ID, to output: inout Output) { + append(operator: .conformanceDecl, to: &output) + append(typeOf: d, to: &output) if let c = program.ast[d].whereClause { - write(whereClause: c.value, to: &output) + append(whereClause: c.value, to: &output) } else { - write(operator: .endOfSequence, to: &output) + append(operator: .endOfSequence, to: &output) } } /// Writes the mangled representation of `d` to `output`. - private mutating func write(extension d: ExtensionDecl.ID, to output: inout Output) { - write(operator: .extensionDecl, to: &output) - mangle(type: program[d].type, to: &output) + private mutating func append(extension d: ExtensionDecl.ID, to output: inout Output) { + append(operator: .extensionDecl, to: &output) + append(typeOf: d, to: &output) if let c = program.ast[d].whereClause { - write(whereClause: c.value, to: &output) + append(whereClause: c.value, to: &output) } else { - write(operator: .endOfSequence, to: &output) + append(operator: .endOfSequence, to: &output) } } /// Writes the mangled representation of `d` to `output`. - private mutating func write(function d: FunctionDecl.ID, to output: inout Output) { + private mutating func append(function d: FunctionDecl.ID, to output: inout Output) { // If the function is anonymous, just encode a unique ID. guard let n = program.ast.name(of: d) else { - write(anonymousScope: AnyScopeID(d), to: &output) + append(anonymous: AnyScopeID(d), to: &output) return } if program.ast[d].isStatic { - write(operator: .staticFunctionDecl, to: &output) + append(operator: .staticFunctionDecl, to: &output) } else { - write(operator: .functionDecl, to: &output) + append(operator: .functionDecl, to: &output) } - write(name: n, to: &output) - write(integer: program.ast[d].genericParameters.count, to: &output) - mangle(type: program[d].type, to: &output) + append(name: n, to: &output) + append(integer: program.ast[d].genericParameters.count, to: &output) + append(typeOf: d, to: &output) } /// Writes the mangled representation of `d` to `output`. - private mutating func write(initializer d: InitializerDecl.ID, to output: inout Output) { + private mutating func append(initializer d: InitializerDecl.ID, to output: inout Output) { // There's at most one memberwise initializer per product type declaration. if program.ast[d].isMemberwise { - write(operator: .memberwiseInitializerDecl, to: &output) + append(operator: .memberwiseInitializerDecl, to: &output) return } // Other initializers are mangled like static member functions. - write(operator: .staticFunctionDecl, to: &output) - write(name: Name(stem: "init"), to: &output) - write(integer: program.ast[d].genericParameters.count, to: &output) - mangle(type: program[d].type, to: &output) + append(operator: .staticFunctionDecl, to: &output) + append(name: Name(stem: "init"), to: &output) + append(integer: program.ast[d].genericParameters.count, to: &output) + append(typeOf: d, to: &output) } /// Writes the mangled representation of `d` to `output`. - private mutating func write(methodDecl d: MethodDecl.ID, to output: inout Output) { - write(operator: .methodDecl, to: &output) - write(string: program.ast[d].identifier.value, to: &output) - mangle(type: program[d].type, to: &output) + private mutating func append(methodDecl d: MethodDecl.ID, to output: inout Output) { + append(operator: .methodDecl, to: &output) + append(string: program.ast[d].identifier.value, to: &output) + append(typeOf: d, to: &output) } /// Writes the mangled representation of `d` to `output`. - private mutating func write(methodImpl d: MethodImpl.ID, to output: inout Output) { - write(operator: .methodImpl, to: &output) - write(base64Digit: program.ast[d].introducer.value, to: &output) + private mutating func append(methodImpl d: MethodImpl.ID, to output: inout Output) { + append(operator: .methodImpl, to: &output) + append(base64Digit: program.ast[d].introducer.value, to: &output) } /// Writes the mangled representation of `d` to `output`. - private mutating func write(subscriptDecl d: SubscriptDecl.ID, to output: inout Output) { + private mutating func append(subscriptDecl d: SubscriptDecl.ID, to output: inout Output) { if program.ast[d].isProperty { - write(operator: .propertyDecl, to: &output) - write(string: program.ast[d].identifier?.value ?? "", to: &output) + append(operator: .propertyDecl, to: &output) + append(string: program.ast[d].identifier?.value ?? "", to: &output) } else { - write(operator: .subscriptDecl, to: &output) - write(string: program.ast[d].identifier?.value ?? "", to: &output) - write(integer: program.ast[d].genericParameters.count, to: &output) + append(operator: .subscriptDecl, to: &output) + append(string: program.ast[d].identifier?.value ?? "", to: &output) + append(integer: program.ast[d].genericParameters.count, to: &output) } - - mangle(type: program[d].type, to: &output) + append(typeOf: d, to: &output) } /// Writes the mangled representation of `u` to `output`. - private mutating func write(subscriptImpl d: SubscriptImpl.ID, to output: inout Output) { - write(operator: .subscriptImpl, to: &output) - write(base64Digit: program.ast[d].introducer.value, to: &output) + private mutating func append(subscriptImpl d: SubscriptImpl.ID, to output: inout Output) { + append(operator: .subscriptImpl, to: &output) + append(base64Digit: program.ast[d].introducer.value, to: &output) } /// Writes the mangled representation of `u` to `output`. - private mutating func write(translationUnit u: TranslationUnit.ID, to output: inout Output) { + private mutating func append(translationUnit u: TranslationUnit.ID, to output: inout Output) { // Note: assumes all files in a module have a different base name. - write(operator: .translatonUnit, to: &output) - write(string: program.ast[u].site.file.baseName, to: &output) + append(operator: .translatonUnit, to: &output) + append(string: program.ast[u].site.file.baseName, to: &output) } /// Writes the mangled representation of `clause` to `output`. - private mutating func write(whereClause clause: WhereClause, to output: inout Output) { - write(operator: .whereClause, to: &output) - write(set: clause.constraints, to: &output) { (m, c) -> String in - var s = "" - m.write(constraint: c.value, to: &s) - return s + private mutating func append(whereClause clause: WhereClause, to output: inout Output) { + append(operator: .whereClause, to: &output) + append(unordered: clause.constraints, to: &output) { (me, c, o) in + me.append(constraint: c.value, to: &o) } } /// Writes the mangled representation of `c` to `output`. - private mutating func write(constraint c: WhereClause.ConstraintExpr, to output: inout Output) { + private mutating func append(constraint c: WhereClause.ConstraintExpr, to output: inout Output) { switch c { case .value: UNIMPLEMENTED() case .bound(let lhs, let rhs): - write(operator: .conformanceConstraint, to: &output) - mangle(type: program[lhs].type, to: &output) - write(integer: rhs.count, to: &output) - for t in rhs { - mangle(type: program[t].type, to: &output) - } + append(operator: .conformanceConstraint, to: &output) + append(typeOf: lhs, to: &output) + append(items: rhs, to: &output) { (me, r, o) in me.append(typeOf: r, to: &o) } case .equality(let lhs, let rhs): - write(operator: .equalityConstraint, to: &output) - mangle(type: program[lhs].type, to: &output) - mangle(type: program[rhs].type, to: &output) + append(operator: .equalityConstraint, to: &output) + append(typeOf: lhs, to: &output) + append(typeOf: rhs, to: &output) } } - /// Writes the mangled representation of `symbol` to `output`. - mutating func mangle(function symbol: Function.ID, to output: inout Output) { - switch symbol.value { + /// Writes the mangled representation of `s` to `output`. + private mutating func append(function s: Function.ID, to output: inout Output) { + switch s.value { case .lowered(let d): - mangle(decl: d, to: &output) + append(decl: d, to: &output) case .monomorphized(let f, let a): - write(monomorphized: f, for: a, to: &output) + append(monomorphized: f, for: a, to: &output) case .synthesized(let d): - write(synthesized: d, to: &output) + append(synthesized: d, to: &output) case .existentialized: UNIMPLEMENTED() } } - /// Writes the mangled representation of `symbol` monomorphized for `arguments` to `output`. - private mutating func write( - monomorphized symbol: Function.ID, for arguments: GenericArguments, to output: inout Output + /// Writes the mangled representation of `s` monomorphized for `arguments` to `output`. + private mutating func append( + monomorphized s: Function.ID, for arguments: GenericArguments, to output: inout Output ) { - write(operator: .monomorphizedFunctionDecl, to: &output) - mangle(function: symbol, to: &output) - write(specialization: arguments, to: &output) + append(operator: .monomorphizedFunctionDecl, to: &output) + append(function: s, to: &output) + append(specialization: arguments, to: &output) } - /// Writes the mangled representation of `specialization` to `output`. - private mutating func write(specialization: GenericArguments, to output: inout Output) { - write(integer: specialization.count, to: &output) - for (_, v) in specialization.sorted(by: \.key.rawValue) { - mangle(value: v, to: &output) + /// Writes the mangled representation of `z` to `output`. + private mutating func append(specialization z: GenericArguments, to output: inout Output) { + append(items: z.sorted(by: \.key.rawValue), to: &output) { (me, a, o) in + me.append(value: a.value, to: &o) } } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write( - synthesized symbol: SynthesizedFunctionDecl, to output: inout Output - ) { - write(operator: .synthesizedFunctionDecl, to: &output) - write(synthesizedKind: symbol.kind, to: &output) - - if symbol.scope.kind != ModuleDecl.self { - writeQualification(of: symbol.scope, to: &output) - } - write(scope: symbol.scope, to: &output) - mangle(type: ^symbol.type, to: &output) + /// Writes the mangled representation of `s` to `output`. + private mutating func append(synthesized s: SynthesizedFunctionDecl, to output: inout Output) { + append(operator: .synthesizedFunctionDecl, to: &output) + append(synthesizedKind: s.kind, to: &output) + appendQualification(of: s.scope, to: &output) + append(scope: s.scope, to: &output) + append(type: ^s.type, to: &output) } /// Writes the mangled representation of `k` to `output`. - private mutating func write( + private mutating func append( synthesizedKind k: SynthesizedFunctionDecl.Kind, to output: inout Output ) { switch k { case .deinitialize: - write(base64Didit: 0, to: &output) + append(base64Didit: 0, to: &output) case .moveInitialization: - write(base64Didit: 1, to: &output) + append(base64Didit: 1, to: &output) case .moveAssignment: - write(base64Didit: 2, to: &output) + append(base64Didit: 2, to: &output) case .copy: - write(base64Didit: 3, to: &output) + append(base64Didit: 3, to: &output) case .equal: - write(base64Didit: 4, to: &output) + append(base64Didit: 4, to: &output) case .globalInitialization(let d): - write(base64Didit: 5, to: &output) - write(entity: d, to: &output) + append(base64Didit: 5, to: &output) + append(entity: d, to: &output) case .autoclosure(let e): - write(base64Didit: 6, to: &output) + append(base64Didit: 6, to: &output) // To allow using multiple autoclosures in the same scope, also write the expression ID. - write(integer: Int(e.rawValue.bits), to: &output) + append(integer: Int(e.rawValue.bits), to: &output) } } - /// Writes the mangled representation of `symbol` to `output`. - mutating func mangle(table symbol: WitnessTable, to output: inout Output) { - write(operator: .witnessTable, to: &output) - write(scope: symbol.scope, to: &output) - mangle(type: symbol.witness, to: &output) + /// Writes the mangled representation of `s` to `output`. + private mutating func append(table s: WitnessTable, to output: inout Output) { + append(operator: .witnessTable, to: &output) + append(scope: s.scope, to: &output) + append(type: program.canonical(s.witness, in: s.scope), to: &output) } - /// Writes the mangled representation of `symbol` to `output`. - mutating func mangle(value symbol: CompileTimeValue, to output: inout Output) { - switch symbol { + /// Writes the mangled representation of `s` to `output`. + private mutating func append(value s: CompileTimeValue, to output: inout Output) { + switch s { case .type(let t): - mangle(type: t, to: &output) + append(type: t, to: &output) case .compilerKnown(let v) where v is Int: - write(integer: v as! Int, to: &output) + append(integer: v as! Int, to: &output) default: UNIMPLEMENTED() } } - /// Writes the mangled representation of `symbol` to `output`. - mutating func mangle(type symbol: AnyType, to output: inout Output) { - let s = program.canonical(symbol, in: scopeOfUse) + /// Writes the mangled representation of `d`'s type to `output`. + private mutating func append(typeOf d: T, to output: inout Output) { + append(type: program.canonical(typeOf: d), to: &output) + } - if writeLookup(.type(s), to: &output) { - return - } + /// Writes the mangled representation of `e`'s type to `output`. + private mutating func append(typeOf e: T, to output: inout Output) { + append(type: program.canonical(typeOf: e), to: &output) + } + + /// Writes the mangled representation of `s` to `output`. + private mutating func append(type s: AnyType, to output: inout Output) { + let n = Symbol.type(s) + if appendIf(reservedOrRecorded: n, to: &output) { return } + assert(s[.isCanonical]) switch s.base { + case let t as ArrowType: + append(arrow: t, to: &output) case let t as AssociatedTypeType: - write(associatedType: t, to: &output) - + append(associatedType: t, to: &output) case let t as BoundGenericType: - write(boundGenericType: t, to: &output) - + append(boundGenericType: t, to: &output) case let t as BufferType: - write(bufferType: t, to: &output) - + append(buffer: t, to: &output) case let t as BuiltinType: - write(builtinType: t, to: &output) - + append(builtin: t, to: &output) case let t as ExistentialType: - write(existentialType: t, to: &output) - + append(existential: t, to: &output) case let t as GenericTypeParameterType: - write(operator: .genericTypeParameterType, to: &output) - mangle(decl: AnyDeclID(t.decl), to: &output) - - case let t as ArrowType: - write(arrow: t, to: &output) - + append(genericTypeParameter: t, to: &output) case let t as MethodType: - write(method: t, to: &output) - + append(method: t, to: &output) case let t as MetatypeType: - write(operator: .metatypeType, to: &output) - mangle(type: t.instance, to: &output) - + append(metatype: t, to: &output) case let t as ParameterType: - write(operator: .parameterType, to: &output) - write(base64Digit: t.access, to: &output) - mangle(type: t.bareType, to: &output) - + append(parameter: t, to: &output) case let t as ProductType: - write(operator: .productType, to: &output) - mangle(decl: AnyDeclID(t.decl), to: &output) - - // End of sequence required because `t.decl` is a scope. - write(operator: .endOfSequence, to: &output) - + append(product: t, to: &output) case let t as RemoteType: - write(operator: .remoteType, to: &output) - write(base64Digit: t.access, to: &output) - mangle(type: t.bareType, to: &output) - + append(remote: t, to: &output) case let t as SubscriptType: - write(subscriptType: t, to: &output) - - case let t as UnionType: - write(unionType: t, to: &output) - + append(subscript: t, to: &output) case let t as TraitType: - write(operator: .traitType, to: &output) - mangle(decl: AnyDeclID(t.decl), to: &output) - - // End of sequence required because `t.decl` is a scope. - write(operator: .endOfSequence, to: &output) - + append(trait: t, to: &output) case let t as TupleType: - write(tupleType: t, to: &output) - + append(tuple: t, to: &output) + case let t as UnionType: + append(union: t, to: &output) default: unreachable() } + symbolPosition[n] = symbolPosition.count + } - symbolID[.type(s)] = nextSymbolID - nextSymbolID += 1 + /// Writes the mangled representation of `t` to `output`. + private mutating func append(arrow t: ArrowType, to output: inout Output) { + append(operator: .arrowType, to: &output) + append(type: t.environment, to: &output) + append(items: t.inputs, to: &output) { (me, i, o) in + me.append(string: i.label ?? "", to: &o) + me.append(type: i.type, to: &o) + } + append(type: t.output, to: &output) } /// Writes the mangled representation of `t` to `output`. - private mutating func write(associatedType t: AssociatedTypeType, to output: inout Output) { - write(operator: .associatedType, to: &output) - mangle(decl: t.decl, to: &output) - mangle(type: t.domain, to: &output) + private mutating func append(associatedType t: AssociatedTypeType, to output: inout Output) { + append(operator: .associatedType, to: &output) + append(decl: t.decl, to: &output) + append(type: t.domain, to: &output) } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(boundGenericType t: BoundGenericType, to output: inout Output) { - write(operator: .boundGenericType, to: &output) - mangle(type: t.base, to: &output) - write(integer: t.arguments.count, to: &output) - for u in t.arguments.values { - mangle(value: u, to: &output) + /// Writes the mangled representation of `t` to `output`. + private mutating func append(boundGenericType t: BoundGenericType, to output: inout Output) { + append(operator: .boundGenericType, to: &output) + append(type: t.base, to: &output) + append(items: t.arguments.values, to: &output) { (me, v, o) in + me.append(value: v, to: &o) } } /// Writes the mangled representation of `t` to `output`. - private mutating func write(bufferType t: BufferType, to output: inout Output) { - write(operator: .bufferType, to: &output) - mangle(type: t.element, to: &output) - mangle(value: t.count, to: &output) + private mutating func append(buffer t: BufferType, to output: inout Output) { + append(operator: .bufferType, to: &output) + append(type: t.element, to: &output) + append(value: t.count, to: &output) } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(builtinType t: BuiltinType, to output: inout Output) { + /// Writes the mangled representation of `z` to `output`. + private mutating func append(builtin t: BuiltinType, to output: inout Output) { switch t { case .i(let width): - write(operator: .builtinIntegerType, to: &output) - write(integer: width, to: &output) + append(operator: .builtinIntegerType, to: &output) + append(integer: width, to: &output) case .word: - write(operator: .builtinWordType, to: &output) + append(operator: .builtinWordType, to: &output) case .float16: - write(operator: .builtinFloatType, to: &output) - write(integer: 16, to: &output) + append(operator: .builtinFloatType, to: &output) + append(integer: 16, to: &output) case .float32: - write(operator: .builtinFloatType, to: &output) - write(integer: 32, to: &output) + append(operator: .builtinFloatType, to: &output) + append(integer: 32, to: &output) case .float64: - write(operator: .builtinFloatType, to: &output) - write(integer: 64, to: &output) + append(operator: .builtinFloatType, to: &output) + append(integer: 64, to: &output) case .float128: - write(operator: .builtinFloatType, to: &output) - write(integer: 128, to: &output) + append(operator: .builtinFloatType, to: &output) + append(integer: 128, to: &output) case .ptr: - write(operator: .builtinPointerType, to: &output) + append(operator: .builtinPointerType, to: &output) case .module: - write(operator: .builtinModuleType, to: &output) + append(operator: .builtinModuleType, to: &output) } } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(existentialType t: ExistentialType, to output: inout Output) { + /// Writes the mangled representation of `t` to `output`. + private mutating func append(existential t: ExistentialType, to output: inout Output) { switch t.interface { case .metatype: - write(operator: .existentialMetatype, to: &output) + append(operator: .existentialMetatype, to: &output) case .generic(let interface): - write(operator: .existentialGenericType, to: &output) - mangle(type: interface, to: &output) + append(operator: .existentialGenericType, to: &output) + append(type: interface, to: &output) case .traits(let interface): - write(operator: .existentialTraitType, to: &output) - write(set: interface, to: &output) { (m, e) -> String in - var s = "" - m.mangle(type: ^e, to: &s) - return s + append(operator: .existentialTraitType, to: &output) + append(unordered: interface, to: &output) { (me, e, o) in + me.append(type: ^e, to: &o) } } } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(arrow t: ArrowType, to output: inout Output) { - write(operator: .arrowType, to: &output) - mangle(type: t.environment, to: &output) - - write(integer: t.inputs.count, to: &output) - for i in t.inputs { - write(string: i.label ?? "", to: &output) - mangle(type: i.type, to: &output) - } - - mangle(type: t.output, to: &output) + /// Writes the mangled representation of `t` to `output`. + private mutating func append( + genericTypeParameter t: GenericTypeParameterType, to output: inout Output + ) { + append(operator: .genericTypeParameterType, to: &output) + append(decl: AnyDeclID(t.decl), to: &output) } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(method t: MethodType, to output: inout Output) { - write(operator: .methodType, to: &output) - write(base64Digit: t.capabilities, to: &output) - mangle(type: t.receiver, to: &output) - - write(integer: t.inputs.count, to: &output) - for i in t.inputs { - write(string: i.label ?? "", to: &output) - mangle(type: i.type, to: &output) + /// Writes the mangled representation of `t` to `output`. + private mutating func append(method t: MethodType, to output: inout Output) { + append(operator: .methodType, to: &output) + append(base64Digit: t.capabilities, to: &output) + append(type: t.receiver, to: &output) + append(items: t.inputs, to: &output) { (me, i, o) in + me.append(string: i.label ?? "", to: &o) + me.append(type: i.type, to: &o) } - - mangle(type: t.output, to: &output) + append(type: t.output, to: &output) } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(subscriptType t: SubscriptType, to output: inout Output) { - write(operator: .subscriptType, to: &output) - write(base64Digit: t.capabilities, to: &output) - mangle(type: t.environment, to: &output) + /// Writes the mangled representation of `t` to `output`. + private mutating func append(metatype t: MetatypeType, to output: inout Output) { + append(operator: .metatypeType, to: &output) + append(type: t.instance, to: &output) + } - write(integer: t.inputs.count, to: &output) - for i in t.inputs { - write(string: i.label ?? "", to: &output) - mangle(type: i.type, to: &output) - } + /// Writes the mangled representation of `t` to `output`. + private mutating func append(parameter t: ParameterType, to output: inout Output) { + append(operator: .parameterType, to: &output) + append(base64Digit: t.access, to: &output) + append(type: t.bareType, to: &output) + } - mangle(type: t.output, to: &output) + /// Writes the mangled representation of `t` to `output`. + private mutating func append(product t: ProductType, to output: inout Output) { + append(operator: .productType, to: &output) + append(decl: AnyDeclID(t.decl), to: &output) + append(operator: .endOfSequence, to: &output) } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(tupleType t: TupleType, to output: inout Output) { - write(operator: .tupleType, to: &output) + /// Writes the mangled representation of `t` to `output`. + private mutating func append(remote t: RemoteType, to output: inout Output) { + append(operator: .remoteType, to: &output) + append(base64Digit: t.access, to: &output) + append(type: t.bareType, to: &output) + } - write(integer: t.elements.count, to: &output) - for e in t.elements { - write(string: e.label ?? "", to: &output) - mangle(type: e.type, to: &output) + /// Writes the mangled representation of `t` to `output`. + private mutating func append(subscript t: SubscriptType, to output: inout Output) { + append(operator: .subscriptType, to: &output) + append(base64Digit: t.capabilities, to: &output) + append(type: t.environment, to: &output) + append(items: t.inputs, to: &output) { (me, i, o) in + me.append(string: i.label ?? "", to: &o) + me.append(type: i.type, to: &o) } + append(type: t.output, to: &output) } - /// Writes the mangled representation of `symbol` to `output`. - private mutating func write(unionType t: UnionType, to output: inout Output) { - write(operator: .unionType, to: &output) - write(set: t.elements, to: &output) { (m, e) -> String in - var s = "" - m.mangle(type: e, to: &s) - return s + /// Writes the mangled representation of `t` to `output`. + private mutating func append(tuple t: TupleType, to output: inout Output) { + append(operator: .tupleType, to: &output) + append(items: t.elements, to: &output) { (me, e, o) in + me.append(string: e.label ?? "", to: &o) + me.append(type: e.type, to: &o) } } - /// If `symbol` is reserved or has already been inserted in the symbol lookup table, writes a - /// lookup reference to it and returns `true`; returns `false` otherwise. - private func writeLookup(_ symbol: Symbol, to output: inout Output) -> Bool { - if let r = reserved[symbol] { - write(operator: .reserved, to: &output) - r.write(to: &output) - return true - } + /// Writes the mangled representation of `t` to `output`. + private mutating func append(trait t: TraitType, to output: inout Output) { + append(operator: .traitType, to: &output) + append(decl: AnyDeclID(t.decl), to: &output) + } - if let i = symbolID[symbol] { - write(operator: .lookup, to: &output) - write(integer: i, to: &output) - return true + /// Writes the mangled representation of `t` to `output`. + private mutating func append(union t: UnionType, to output: inout Output) { + append(operator: .unionType, to: &output) + append(unordered: t.elements, to: &output) { (me, e, o) in + me.append(type: e, to: &o) } - - return false } /// Writes the mangled representation of `name` to `output`. - private func write(name: Name, to output: inout Output) { + private func append(name: Name, to output: inout Output) { // Only encode notation and introducer; labels are encoded in types. var tag: UInt8 = 0 if name.notation != nil { tag = 1 } if name.introducer != nil { tag = tag | 2 } - write(base64Didit: tag, to: &output) + append(base64Didit: tag, to: &output) if let n = name.notation { - write(base64Digit: n, to: &output) + append(base64Digit: n, to: &output) } if let i = name.introducer { - write(base64Digit: i, to: &output) + append(base64Digit: i, to: &output) } - write(string: name.stem, to: &output) + append(string: name.stem, to: &output) } /// Writes `string` to `output`, prefixed by its length encoded as a variable-length integer. - private func write(string: T, to output: inout Output) { - write(integer: string.count, to: &output) + private func append(string: T, to output: inout Output) { + append(integer: string.count, to: &output) string.write(to: &output) } /// Writes `v` encoded as a variable-length integer to `output`. - private func write(integer v: Int, to output: inout Output) { + private func append(integer v: Int, to output: inout Output) { Base64VarUInt(v).write(to: &output) } /// Writes the raw value of `v` encoded as a base 64 digit to `output`. - private func write( - base64Digit v: T, to output: inout Output - ) where T.RawValue == UInt8 { - write(base64Didit: v.rawValue, to: &output) + private func append>(base64Digit v: T, to output: inout Output) { + append(base64Didit: v.rawValue, to: &output) } /// Writes `v` encoded as a base 64 digit to `output`. - private func write(base64Didit v: UInt8, to output: inout Output) { + private func append(base64Didit v: UInt8, to output: inout Output) { Base64Digit(rawValue: v)!.description.write(to: &output) } /// Writes `o` to `output`. - private func write(operator o: ManglingOperator, to output: inout Output) { + private func append(operator o: ManglingOperator, to output: inout Output) { o.write(to: &output) } - /// Writes the mangled representation of `elements`, which is an unordered set, calling - /// `mangleElement` to mangle individual elements. - private mutating func write( - set elements: S, to output: inout Output, - manglingElementsWith mangleElement: (inout Self, S.Element) -> String + /// Writes the mangled representation of `items`, calling `appendItem` to mangle each individual + /// element to `output`. + private mutating func append( + items: T, to output: inout Output, + appendingEachWith appendItem: (inout Self, T.Element, inout Output) -> Void ) { - write(integer: elements.count, to: &output) + append(integer: items.count, to: &output) + for i in items { + appendItem(&self, i, &output) + } + } + /// Writes the mangled representation of `items`, which is an unordered set, calling `mangleItem` + /// to mangle each individual element. + private func append( + unordered items: T, to output: inout Output, + manglingElementsWith mangleItem: (inout Self, T.Element, inout Output) -> Void + ) { + append(integer: items.count, to: &output) var mangled: [String] = [] - for e in elements { + for e in items { // Copy `self` to share the symbol looking table built so far. var m = self - let s = mangleElement(&m, e) + var s = "" + mangleItem(&m, e, &s) let i = mangled.partitioningIndex(where: { s < $0 }) mangled.insert(s, at: i) } - mangled.joined().write(to: &output) } + /// If `s` is reserved or has already been inserted in the symbol lookup table, writes a lookup + /// reference to it and returns `true`. Otherwise, returns `false`. + private func appendIf(reservedOrRecorded s: Symbol, to output: inout Output) -> Bool { + appendIf(reserved: s, to: &output) || appendIf(recorded: s, to: &output) + } + + /// Writes a lookup reference to `s` and returns `true` iff `s` is a reserved symbol. Otherwise, + /// returns `false` without modifying `output`. + private func appendIf(reserved s: Symbol, to output: inout Output) -> Bool { + if let r = reserved[s] { + append(operator: .reserved, to: &output) + r.write(to: &output) + return true + } else { + return false + } + } + + /// Writes a lookup reference to `s` and returns `true` iff `s` in the lookup table. Otherwise, + /// returns `false` without modifying `output`. + private func appendIf(recorded s: Symbol, to output: inout Output) -> Bool { + if let p = symbolPosition[s] { + append(operator: .lookup, to: &output) + append(integer: p, to: &output) + return true + } else { + return false + } + } + } diff --git a/Sources/IR/Mangling/ManglingOperator.swift b/Sources/IR/Mangling/ManglingOperator.swift index e165ff109..337ba7417 100644 --- a/Sources/IR/Mangling/ManglingOperator.swift +++ b/Sources/IR/Mangling/ManglingOperator.swift @@ -6,6 +6,8 @@ public enum ManglingOperator: String { case productTypeDecl = "A" + case bindingDecl = "bD" + case traitDecl = "C" case conformanceDecl = "cD" @@ -44,6 +46,8 @@ public enum ManglingOperator: String { case lookup = "K" + case lookupRelative = "rK" + case moduleDecl = "M" case namespaceDecl = "N" diff --git a/Sources/IR/Mangling/TypedProgram+Mangling.swift b/Sources/IR/Mangling/TypedProgram+Mangling.swift index 0f2f28e31..9d59590f1 100644 --- a/Sources/IR/Mangling/TypedProgram+Mangling.swift +++ b/Sources/IR/Mangling/TypedProgram+Mangling.swift @@ -4,33 +4,30 @@ extension TypedProgram { /// Returns the mangled representation of `d`. public func mangled(_ d: T) -> String { - mangled(d, applying: { (s, m, o) in m.mangle(decl: s, to: &o) }) + mangled(d, applying: { (s, m) in m.mangled(decl: s) }) } /// Returns the mangled representation of `t`. public func mangled(_ t: T) -> String { - mangled(^t, applying: { (s, m, o) in m.mangle(type: s, to: &o) }) + mangled(^t, applying: { (s, m) in m.mangled(type: s) }) } /// Returns the mangled representation of `w`. public func mangled(_ w: WitnessTable) -> String { - mangled(w, applying: { (s, m, o) in m.mangle(table: s, to: &o) }) + mangled(w, applying: { (s, m) in m.mangled(table: s) }) } /// Returns the mangled representation of `f`. public func mangled(_ f: Function.ID) -> String { - mangled(f, applying: { (s, m, o) in m.mangle(function: s, to: &o) }) + mangled(f, applying: { (s, m) in m.mangled(function: s) }) } - /// Returns the mangled representation of `symbol` in `scopeOfuse`, applying `mangle` to compute - /// that representation. + /// Returns the mangled representation of `s`, applying `mangle` to build it. private func mangled( - _ symbol: T, applying mangle: (T, inout Mangler, inout String) -> Void + _ s: T, applying mangle: (T, inout Mangler) -> String ) -> String { - var output = "" - var m = Mangler(self, in: AnyScopeID(ast.coreLibrary!)) // FIXME: use actual scope - mangle(symbol, &m, &output) - return output.assemblySanitized + var m = Mangler(self) + return mangle(s, &m).assemblySanitized } } From 43c8ec0c6380c8d083c7657186346363e2fcfd37 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 30 Aug 2024 13:55:46 +0200 Subject: [PATCH 4/9] Fix the demangler --- Sources/IR/Mangling/DemangledEntity.swift | 36 +++-- .../IR/Mangling/DemangledQualification.swift | 41 +++++ Sources/IR/Mangling/DemangledSymbol.swift | 17 ++- .../DemangledSynthesizedFunction.swift | 49 ++++++ Sources/IR/Mangling/DemangledType.swift | 4 +- Sources/IR/Mangling/Demangler.swift | 142 ++++++++++++++---- Sources/IR/Mangling/Mangler.swift | 1 + Tests/ManglingTests/ManglingTests.swift | 2 +- 8 files changed, 243 insertions(+), 49 deletions(-) create mode 100644 Sources/IR/Mangling/DemangledQualification.swift create mode 100644 Sources/IR/Mangling/DemangledSynthesizedFunction.swift diff --git a/Sources/IR/Mangling/DemangledEntity.swift b/Sources/IR/Mangling/DemangledEntity.swift index 940544774..8a0024649 100644 --- a/Sources/IR/Mangling/DemangledEntity.swift +++ b/Sources/IR/Mangling/DemangledEntity.swift @@ -5,7 +5,7 @@ import Utils public struct DemangledEntity: Hashable { /// The qualification of the symbol, if any. - public let qualification: Indirect? + public let qualification: DemangledQualification? /// The kind of the symbol, if known. public let kind: NodeKind? @@ -24,13 +24,13 @@ public struct DemangledEntity: Hashable { /// Creates an instance with the given properties. public init( - qualification: DemangledEntity?, + qualification: DemangledQualification?, kind: NodeKind, name: Name, genericArgumentLabels: [String?] = [], type: DemangledType? = nil ) { - self.qualification = qualification.map(Indirect.init(_:)) + self.qualification = qualification self.kind = kind self.name = name self.genericArgumentLabels = genericArgumentLabels @@ -39,8 +39,8 @@ public struct DemangledEntity: Hashable { } /// Creates an instance identifying an anonymous scope. - public init(anonymousScope id: Int, qualifiedBy q: DemangledEntity) { - self.qualification = Indirect(q) + public init(anonymousScope id: Int, qualifiedBy q: DemangledQualification) { + self.qualification = q self.kind = nil self.name = Name(stem: id.description) self.genericArgumentLabels = [] @@ -51,7 +51,9 @@ public struct DemangledEntity: Hashable { /// Creates an instance representing a core type declaration. public init(coreType: String) { self.init( - qualification: .hylo, kind: NodeKind(ProductTypeDecl.self), name: Name(stem: coreType)) + qualification: .entity(.hylo), + kind: NodeKind(ProductTypeDecl.self), + name: Name(stem: coreType)) } /// The `Hylo` module. @@ -121,20 +123,26 @@ extension DemangledEntity: CustomStringConvertible { } let i = inputs.reduce(into: "", { (s, p) in s += (p.label ?? "_") + ":" }) - return "\(name)(\(i))" + return "\(name)[\(i)]" } /// Returns the textual description of a qualification. - private static func describe(qualification: Indirect?) -> String { - guard let q = qualification else { + private static func describe(qualification: DemangledQualification?) -> String { + switch qualification { + case .some(.entity(let q)): + if q.kind?.value == TranslationUnit.self { + return describe(qualification: q.qualification) + } else { + return q.description + "." + } + + case .some(let q): + return q.description + + case nil: return "" } - if q.value.kind?.value == TranslationUnit.self { - return describe(qualification: q.value.qualification) - } else { - return q.description + "." - } } } diff --git a/Sources/IR/Mangling/DemangledQualification.swift b/Sources/IR/Mangling/DemangledQualification.swift new file mode 100644 index 000000000..b4d5f29b4 --- /dev/null +++ b/Sources/IR/Mangling/DemangledQualification.swift @@ -0,0 +1,41 @@ +/// The demangled qualification of a symbol. +public indirect enum DemangledQualification: Hashable { + + /// An entity. + case entity(DemangledEntity) + + /// A reference to the innermost enclosing entity. + case relative + + /// Creates an instance wrapping `e` iff it is not `nil`. + init?(_ e: DemangledEntity?) { + if let s = e { + self = .entity(s) + } else { + return nil + } + } + + /// The entity wrapped in `self` if its payload is `.entity`, or `nil` otherwise. + public var entity: DemangledEntity? { + if case .entity(let e) = self { + return e + } else { + return nil + } + } + +} + +extension DemangledQualification: CustomStringConvertible { + + public var description: String { + switch self { + case .entity(let d): + return d.description + case .relative: + return ".." + } + } + +} diff --git a/Sources/IR/Mangling/DemangledSymbol.swift b/Sources/IR/Mangling/DemangledSymbol.swift index 5c099ddcc..642e712c4 100644 --- a/Sources/IR/Mangling/DemangledSymbol.swift +++ b/Sources/IR/Mangling/DemangledSymbol.swift @@ -1,7 +1,7 @@ import Utils /// The demangled description of a or entity. -public enum DemangledSymbol: Hashable { +public indirect enum DemangledSymbol: Hashable { /// Creates an instance decoding the symbol mangled in `s`, returning `nil` if decoding failed. public init?(_ s: String) { @@ -41,6 +41,15 @@ public enum DemangledSymbol: Hashable { /// The declaration of an entity or bundle. case entity(DemangledEntity) + /// A binding declaration. + case binding(names: [DemangledEntity]) + + /// A synthesized declaration. + case synthesized(DemangledSynthesizedFunction) + + /// A monomorphized symbols. + case monomorphized(DemangledSymbol, arguments: [DemangledSymbol]) + /// A type. case type(DemangledType) @@ -61,6 +70,12 @@ extension DemangledSymbol: CustomStringConvertible { switch self { case .entity(let e): return e.description + case .binding(let n): + return n.description + case .synthesized(let d): + return d.description + case .monomorphized(let e, let z): + return "\(e) for \(z)" case .type(let t): return t.description } diff --git a/Sources/IR/Mangling/DemangledSynthesizedFunction.swift b/Sources/IR/Mangling/DemangledSynthesizedFunction.swift new file mode 100644 index 000000000..9253ae70f --- /dev/null +++ b/Sources/IR/Mangling/DemangledSynthesizedFunction.swift @@ -0,0 +1,49 @@ +import Utils + +/// The demangled description of a synthesized function. +public struct DemangledSynthesizedFunction: Hashable { + + /// The kind of a synthesized declaration. + public indirect enum Kind: Hashable { + + /// A deinitializer. + case deinitialize + + /// A move-initialization method. + case moveInitialization + + /// A move-assignment method. + case moveAssignment + + /// A copy method. + case copy + + /// An equality method. + case equal + + /// A global initializer for a binding declaration. + case globalInitialization(DemangledSymbol) + + /// Lambda generated for an autoclosure argument. + case autoclosure(Int) + + } + + /// The type of this declaration. + public let type: DemangledType + + /// The scope in which the declaration is defined. + public let scope: Indirect + + /// The kind of the declaration. + public let kind: Kind + +} + +extension DemangledSynthesizedFunction: CustomStringConvertible { + + public var description: String { + "\(scope).\(kind)" + } + +} diff --git a/Sources/IR/Mangling/DemangledType.swift b/Sources/IR/Mangling/DemangledType.swift index d4f0e4827..c071f0878 100644 --- a/Sources/IR/Mangling/DemangledType.swift +++ b/Sources/IR/Mangling/DemangledType.swift @@ -98,7 +98,7 @@ extension DemangledType: CustomStringConvertible { let i = inputs.map { (p) -> String in (p.label.map({ $0 + ": " }) ?? "") + p.type.description } - return "[\(environment)](\(list: i) \(effect) -> \(output)" + return "[\(environment)](\(list: i)) \(effect) -> \(output)" case .associatedType(let domain, let name): return "\(domain).\(name)" @@ -135,7 +135,7 @@ extension DemangledType: CustomStringConvertible { (p.label.map({ $0 + ": " }) ?? "") + p.type.description } let cs = capabilities.elements.descriptions(joinedBy: " ") - return "[\(environment)](\(list: i) : \(output) { \(cs) }" + return "[\(environment)](\(list: i)) : \(output) { \(cs) }" case .union(let elements): return "Union<\(list: elements)>" diff --git a/Sources/IR/Mangling/Demangler.swift b/Sources/IR/Mangling/Demangler.swift index 7fed511fe..326c4af0b 100644 --- a/Sources/IR/Mangling/Demangler.swift +++ b/Sources/IR/Mangling/Demangler.swift @@ -11,7 +11,7 @@ struct Demangler { /// Demangles a symbol from `stream`. mutating func demangle(from stream: inout Substring) -> DemangledSymbol? { - var qualification: DemangledEntity? = nil + var qualification: DemangledQualification? = nil while let o = takeOperator(from: &stream) { let demangled: DemangledSymbol? @@ -19,12 +19,16 @@ struct Demangler { switch o { case .anonymousScope: demangled = takeAnonymousScope(qualifiedBy: qualification, from: &stream) + case .arrowType: + demangled = takeArrowType(from: &stream) case .associatedType: demangled = takeAssociatedType(from: &stream) case .associatedTypeDecl: demangled = take(AssociatedTypeDecl.self, qualifiedBy: qualification, from: &stream) case .associatedValueDecl: demangled = take(AssociatedValueDecl.self, qualifiedBy: qualification, from: &stream) + case .bindingDecl: + demangled = takeBindingDecl(qualifiedBy: qualification, from: &stream) case .boundGenericType: demangled = takeBoundGenericType(from: &stream) case .bufferType: @@ -61,8 +65,6 @@ struct Demangler { demangled = takeNominalType(declaredBy: GenericParameterDecl.self, from: &stream) case .importDecl: demangled = take(ImportDecl.self, qualifiedBy: qualification, from: &stream) - case .arrowType: - demangled = takeArrowType(from: &stream) case .lookup: demangled = takeLookup(from: &stream) case .memberwiseInitializerDecl: @@ -71,6 +73,8 @@ struct Demangler { demangled = takeMetatypeType(from: &stream) case .moduleDecl: demangled = takeModuleDecl(from: &stream) + case .monomorphizedFunctionDecl: + demangled = takeMonomorphizedFunctionDecl(from: &stream) case .namespaceDecl: demangled = take(NamespaceDecl.self, qualifiedBy: qualification, from: &stream) case .parameterDecl: @@ -95,6 +99,8 @@ struct Demangler { demangled = takeSubscriptImpl(qualifiedBy: qualification, from: &stream) case .subscriptType: demangled = takeSubscriptType(from: &stream) + case .synthesizedFunctionDecl: + demangled = takeSynthesizedFunctionDecl(from: &stream) case .traitDecl: demangled = take(TraitDecl.self, qualifiedBy: qualification, from: &stream) case .traitType: @@ -111,24 +117,20 @@ struct Demangler { demangled = take(VarDecl.self, qualifiedBy: qualification, from: &stream) case .lookupRelative: - fatalError() - case .bindingDecl: - fatalError() + qualification = .relative + continue + case .subscriptImplType: fatalError() case .existentializedFunctionDecl: return nil - case .monomorphizedFunctionDecl: - return nil case .methodDecl: return nil case .methodImpl: return nil case .methodType: return nil - case .synthesizedFunctionDecl: - return nil case .conformanceConstraint, .equalityConstraint, .valueConstraint, .whereClause: return nil case .witnessTable: @@ -137,13 +139,13 @@ struct Demangler { // End of sequence reached if `demangled` is `nil`. guard let d = demangled else { break } - if (o != .lookup) && (o != .reserved) { + if (o != .lookup) && (o != .lookupRelative) && (o != .reserved) { symbols.append(d) } // Update the context and look for the next symbol if we demangled a scope. if let e = d.entity, e.isScope { - qualification = e + qualification = .entity(e) continue } @@ -151,7 +153,7 @@ struct Demangler { return d } - if let e = qualification { + if let e = qualification?.entity { return .entity(e) } else { return nil @@ -180,7 +182,7 @@ struct Demangler { /// Demangles an entity declaration of type `T` from `stream`. private mutating func take( - _: T.Type, qualifiedBy qualification: DemangledEntity?, + _: T.Type, qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -192,7 +194,7 @@ struct Demangler { /// Demangles an conformance declaration from `stream`. private mutating func take( - _: T.Type, qualifiedBy qualification: DemangledEntity?, + _: T.Type, qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -219,7 +221,7 @@ struct Demangler { /// Demangles an anonymous scope from `stream`. private mutating func takeAnonymousScope( - qualifiedBy qualification: DemangledEntity?, + qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -229,9 +231,26 @@ struct Demangler { return .entity(.init(anonymousScope: Int(i.rawValue), qualifiedBy: q)) } + /// Demangles a binding declaration from `stream`. + private mutating func takeBindingDecl( + qualifiedBy qualification: DemangledQualification?, + from stream: inout Substring + ) -> DemangledSymbol? { + guard let n = takeInteger(from: &stream) else { return nil } + + var vs: [DemangledEntity] = [] + vs.reserveCapacity(Int(n.rawValue)) + for _ in 0 ..< n.rawValue { + guard let a = demangle(from: &stream)?.entity else { return nil } + vs.append(a) + } + + return .binding(names: vs) + } + /// Demangles a function from `stream`. private mutating func takeFunctionDecl( - qualifiedBy qualification: DemangledEntity?, + qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -250,9 +269,67 @@ struct Demangler { return .entity(e) } + /// Demangles a synthesized function from `stream`. + private mutating func takeSynthesizedFunctionDecl( + from stream: inout Substring + ) -> DemangledSymbol? { + guard + let k = takeSynthesizedFunctionDeclKind(from: &stream), + let s = demangle(from: &stream), + let t = demangleType(from: &stream) + else { return nil } + return .synthesized(.init(type: t, scope: .init(s), kind: k)) + } + + /// Demangles the kind of a synthesized function from `stream`. + private mutating func takeSynthesizedFunctionDeclKind( + from stream: inout Substring + ) -> DemangledSynthesizedFunction.Kind? { + guard let k = takeBase64Digit(from: &stream) else { return nil } + switch k.rawValue { + case 0: return .deinitialize + case 1: return .moveInitialization + case 2: return .moveAssignment + case 3: return .copy + case 4: return .equal + case 5: return takeSynthesizedGlobalInitializationKind(from: &stream) + case 6: return takeSynthesizedAutoclosureKind(from: &stream) + default: return nil + } + } + + /// Demangles the kind of a synthesized global initializer from `stream`. + private mutating func takeSynthesizedGlobalInitializationKind( + from stream: inout Substring + ) -> DemangledSynthesizedFunction.Kind? { + demangle(from: &stream).map { (d) in + DemangledSynthesizedFunction.Kind.globalInitialization(d) + } + } + + /// Demangles the kind of a synthesized autoclosure from `stream`. + private func takeSynthesizedAutoclosureKind( + from stream: inout Substring + ) -> DemangledSynthesizedFunction.Kind? { + takeInteger(from: &stream).map { (n) in + DemangledSynthesizedFunction.Kind.autoclosure(Int(n.rawValue)) + } + } + + /// Demangles a monomorphized function from `stream`. + private mutating func takeMonomorphizedFunctionDecl( + from stream: inout Substring + ) -> DemangledSymbol? { + guard + let f = demangle(from: &stream), + let z = takeGenericArguments(from: &stream) + else { return nil } + return .monomorphized(f, arguments: z) + } + /// Demangles a memberwise initializer from `stream`. private func takeMemberwiseInitializerDecl( - qualifiedBy qualification: DemangledEntity?, + qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -279,7 +356,7 @@ struct Demangler { /// Demangles a property declaration from `stream`. private mutating func takePropertyDecl( - qualifiedBy qualification: DemangledEntity?, + qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -298,7 +375,7 @@ struct Demangler { /// Demangles a property declaration from `stream`. private mutating func takeSubscriptDecl( - qualifiedBy qualification: DemangledEntity?, + qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -319,7 +396,7 @@ struct Demangler { /// Demangles a property declaration from `stream`. private mutating func takeSubscriptImpl( - qualifiedBy qualification: DemangledEntity?, + qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { guard @@ -372,19 +449,22 @@ struct Demangler { private mutating func takeBoundGenericType(from stream: inout Substring) -> DemangledSymbol? { guard let b = demangleType(from: &stream), - let argumentCount = takeInteger(from: &stream) + let z = takeGenericArguments(from: &stream) else { return nil } - var parameterization: [DemangledSymbol] = [] - parameterization.reserveCapacity(Int(argumentCount.rawValue)) - for _ in 0 ..< argumentCount.rawValue { - guard - let a = demangle(from: &stream) - else { return nil } - parameterization.append(a) - } + return .type(.boundGeneric(base: b, arguments: z)) + } - return .type(.boundGeneric(base: b, arguments: parameterization)) + /// Demangles a list of generic arguments from `stream`. + private mutating func takeGenericArguments(from stream: inout Substring) -> [DemangledSymbol]? { + guard let n = takeInteger(from: &stream) else { return nil } + var z: [DemangledSymbol] = [] + z.reserveCapacity(Int(n.rawValue)) + for _ in 0 ..< n.rawValue { + guard let a = demangle(from: &stream) else { return nil } + z.append(a) + } + return z } /// Demangles a buffer type from `stream`. diff --git a/Sources/IR/Mangling/Mangler.swift b/Sources/IR/Mangling/Mangler.swift index 85bd45713..2a00fb5ef 100644 --- a/Sources/IR/Mangling/Mangler.swift +++ b/Sources/IR/Mangling/Mangler.swift @@ -385,6 +385,7 @@ struct Mangler { append(synthesizedKind: s.kind, to: &output) appendQualification(of: s.scope, to: &output) append(scope: s.scope, to: &output) + append(operator: .endOfSequence, to: &output) append(type: ^s.type, to: &output) } diff --git a/Tests/ManglingTests/ManglingTests.swift b/Tests/ManglingTests/ManglingTests.swift index 18a3d47ea..0c8c43187 100644 --- a/Tests/ManglingTests/ManglingTests.swift +++ b/Tests/ManglingTests/ManglingTests.swift @@ -81,7 +81,7 @@ final class ManglingTests: XCTestCase { "Main.Stash", "Main.Stash.A", "Main.Angle.init", - "Main.Angle.degrees().inout", + "Main.Angle.degrees[].inout", "Main.français(_:label:).bar", ] From 94aba3a3461b24343b276da7e8673a0854f812ab Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 30 Aug 2024 14:02:25 +0200 Subject: [PATCH 5/9] Refactor the demangler --- Sources/IR/Mangling/Demangler.swift | 71 +++++++++-------------------- 1 file changed, 21 insertions(+), 50 deletions(-) diff --git a/Sources/IR/Mangling/Demangler.swift b/Sources/IR/Mangling/Demangler.swift index 326c4af0b..1b19d056b 100644 --- a/Sources/IR/Mangling/Demangler.swift +++ b/Sources/IR/Mangling/Demangler.swift @@ -164,20 +164,20 @@ struct Demangler { private mutating func demangleEntity( _: T.Type, from stream: inout Substring ) -> DemangledEntity? { - guard - case .entity(let e) = demangle(from: &stream), - e.kind?.value == T.self - else { return nil } - - return e + if case .entity(let e) = demangle(from: &stream), e.kind?.value == T.self { + return e + } else { + return nil + } } /// Demangles a type from `stream`. private mutating func demangleType(from stream: inout Substring) -> DemangledType? { - guard case .type(let t) = demangle(from: &stream) else { + if case .type(let t) = demangle(from: &stream) { + return t + } else { return nil } - return t } /// Demangles an entity declaration of type `T` from `stream`. @@ -413,27 +413,17 @@ struct Demangler { /// Demangles a direct declaration reference from `stream`. private mutating func takeDirectDeclReference(from stream: inout Substring) -> DemangledSymbol? { - guard - let e = demangle(from: &stream) - else { return nil } - print(e) - return nil + UNIMPLEMENTED() } /// Demangles a reference to a symbol from `stream`. private mutating func takeLookup(from stream: inout Substring) -> DemangledSymbol? { - guard - let position = takeInteger(from: &stream) - else { return nil } - return symbols[Int(position.rawValue)] + takeInteger(from: &stream).flatMap({ (n) in symbols[Int(n.rawValue)] }) } /// Demangles a reserved symbol from `stream`. private mutating func takeReserved(from stream: inout Substring) -> DemangledSymbol? { - guard - let r = take(ReservedSymbol.self, from: &stream) - else { return nil } - return DemangledSymbol(reserved: r) + take(ReservedSymbol.self, from: &stream).map(DemangledSymbol.init(reserved:)) } /// Demangles an associated type from `stream`. @@ -478,26 +468,19 @@ struct Demangler { /// Demangles a built-in integer type from `stream`. private mutating func takeBuiltinIntegerType(from stream: inout Substring) -> DemangledSymbol? { - guard - let width = takeInteger(from: &stream) - else { return nil } - return .type(.builtin(.i(Int(width.rawValue)))) + takeInteger(from: &stream).map({ (w) in .type(.builtin(.i(Int(w.rawValue)))) }) } /// Demangles a built-in float type from `stream`. private mutating func takeBuiltinFloatType(from stream: inout Substring) -> DemangledSymbol? { - guard - let width = takeInteger(from: &stream) - else { return nil } - - switch width.rawValue { - case 16: + switch takeInteger(from: &stream)?.rawValue { + case .some(16): return .type(.builtin(.float16)) - case 32: + case .some(32): return .type(.builtin(.float32)) - case 64: + case .some(64): return .type(.builtin(.float64)) - case 128: + case .some(128): return .type(.builtin(.float128)) default: return nil @@ -508,10 +491,7 @@ struct Demangler { private mutating func takeExistentialGenericType( from stream: inout Substring ) -> DemangledSymbol? { - guard - let interface = demangleType(from: &stream) - else { return nil } - return .type(.existentialGeneric(interface)) + demangleType(from: &stream).map({ (i) in .type(.existentialGeneric(i)) }) } /// Demangles an existential generic type from `stream`. @@ -562,18 +542,12 @@ struct Demangler { private mutating func takeNominalType( declaredBy _: T.Type, from stream: inout Substring ) -> DemangledSymbol? { - guard - let e = demangleEntity(T.self, from: &stream) - else { return nil } - return .type(.nominal(e)) + demangleEntity(T.self, from: &stream).map({ (e) in .type(.nominal(e)) }) } /// Demangles a metatype from `stream`. private mutating func takeMetatypeType(from stream: inout Substring) -> DemangledSymbol? { - guard - let instance = demangleType(from: &stream) - else { return nil } - return .type(.metatype(instance)) + demangleType(from: &stream).map({ (t) in .type(.metatype(t)) }) } /// Demangles a parameter type from `stream`. @@ -743,10 +717,7 @@ struct Demangler { private func take( _: T.Type, from stream: inout Substring ) -> T? where T.RawValue == UInt8 { - guard let d = takeBase64Digit(from: &stream) else { - return nil - } - return T(rawValue: d.rawValue) + takeBase64Digit(from: &stream).flatMap({ (d) in T(rawValue: d.rawValue) }) } } From 29aff21966996f6b430362f2d106cbe8ae0c3463 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 30 Aug 2024 14:19:22 +0200 Subject: [PATCH 6/9] Refactor the demangler --- Sources/IR/Mangling/Demangler.swift | 115 ++++++++++------------------ 1 file changed, 42 insertions(+), 73 deletions(-) diff --git a/Sources/IR/Mangling/Demangler.swift b/Sources/IR/Mangling/Demangler.swift index 1b19d056b..410d39619 100644 --- a/Sources/IR/Mangling/Demangler.swift +++ b/Sources/IR/Mangling/Demangler.swift @@ -236,16 +236,10 @@ struct Demangler { qualifiedBy qualification: DemangledQualification?, from stream: inout Substring ) -> DemangledSymbol? { - guard let n = takeInteger(from: &stream) else { return nil } - - var vs: [DemangledEntity] = [] - vs.reserveCapacity(Int(n.rawValue)) - for _ in 0 ..< n.rawValue { - guard let a = demangle(from: &stream)?.entity else { return nil } - vs.append(a) + let vs = takeItems(from: &stream) { (me, s) in + me.demangle(from: &s)?.entity } - - return .binding(names: vs) + return vs.map({ (ns) in .binding(names: ns) }) } /// Demangles a function from `stream`. @@ -447,14 +441,7 @@ struct Demangler { /// Demangles a list of generic arguments from `stream`. private mutating func takeGenericArguments(from stream: inout Substring) -> [DemangledSymbol]? { - guard let n = takeInteger(from: &stream) else { return nil } - var z: [DemangledSymbol] = [] - z.reserveCapacity(Int(n.rawValue)) - for _ in 0 ..< n.rawValue { - guard let a = demangle(from: &stream) else { return nil } - z.append(a) - } - return z + takeItems(from: &stream, takingEachWith: { (me, s) in me.demangle(from: &s) }) } /// Demangles a buffer type from `stream`. @@ -498,40 +485,17 @@ struct Demangler { private mutating func takeExistentialTraitType( from stream: inout Substring ) -> DemangledSymbol? { - guard - let traitCount = takeInteger(from: &stream) - else { return nil } - - var traits: [DemangledType] = [] - traits.reserveCapacity(Int(traitCount.rawValue)) - for _ in 0 ..< traitCount.rawValue { - guard - let t = demangleType(from: &stream) - else { return nil } - traits.append(t) + let ts = takeItems(from: &stream) { (me, s) in + me.demangleType(from: &s) } - - return .type(.existentialTrait(traits)) + return ts.map({ (s) in .type(.existentialTrait(s))}) } /// Demangles an arrow type from `stream`. private mutating func takeArrowType(from stream: inout Substring) -> DemangledSymbol? { guard let environment = demangleType(from: &stream), - let inputCount = takeInteger(from: &stream) - else { return nil } - - var inputs: [DemangledType.Parameter] = [] - inputs.reserveCapacity(Int(inputCount.rawValue)) - for _ in 0 ..< inputCount.rawValue { - guard - let l = takeString(from: &stream), - let t = demangleType(from: &stream) - else { return nil } - inputs.append(.init(label: l.isEmpty ? nil : String(l), type: t)) - } - - guard + let inputs = takeParameters(from: &stream), let output = demangleType(from: &stream) else { return nil } @@ -573,20 +537,7 @@ struct Demangler { guard let capabilities = take(AccessEffectSet.self, from: &stream), let environment = demangleType(from: &stream), - let inputCount = takeInteger(from: &stream) - else { return nil } - - var inputs: [DemangledType.Parameter] = [] - inputs.reserveCapacity(Int(inputCount.rawValue)) - for _ in 0 ..< inputCount.rawValue { - guard - let l = takeString(from: &stream), - let t = demangleType(from: &stream) - else { return nil } - inputs.append(.init(label: l.isEmpty ? nil : String(l), type: t)) - } - - guard + let inputs = takeParameters(from: &stream), let output = demangleType(from: &stream) else { return nil } @@ -597,21 +548,7 @@ struct Demangler { /// Demangles a tuple type from `stream`. private mutating func takeTupleType(from stream: inout Substring) -> DemangledSymbol? { - guard - let count = takeInteger(from: &stream) - else { return nil } - - var elements: [DemangledType.Parameter] = [] - elements.reserveCapacity(Int(count.rawValue)) - for _ in 0 ..< count.rawValue { - guard - let l = takeString(from: &stream), - let t = demangleType(from: &stream) - else { return nil } - elements.append(.init(label: l.isEmpty ? nil : String(l), type: t)) - } - - return .type(.tuple(elements)) + takeParameters(from: &stream).map({ (s) in .type(.tuple(s)) }) } /// Demangles a union type from `stream`. @@ -634,6 +571,22 @@ struct Demangler { return .type(.union(elements)) } + /// Demangles a list of parameters or tuple elements from `stream`. + private mutating func takeParameters( + from stream: inout Substring + ) -> [DemangledType.Parameter]? { + takeItems(from: &stream, takingEachWith: { (me, s) in me.takeParameter(from: &s) }) + } + + /// Demangles a parameter or tuple element from `stream`. + private mutating func takeParameter(from stream: inout Substring) -> DemangledType.Parameter? { + guard + let l = takeString(from: &stream), + let t = demangleType(from: &stream) + else { return nil } + return .init(label: l.isEmpty ? nil : String(l), type: t) + } + /// If `stream` starts with a mangling operator, consumes and returns it; returns /// `nil` without mutating `stream` otherwise. private func takeOperator(from stream: inout Substring) -> ManglingOperator? { @@ -720,4 +673,20 @@ struct Demangler { takeBase64Digit(from: &stream).flatMap({ (d) in T(rawValue: d.rawValue) }) } + /// Demangles a list of `T`s from `stream`, calling `takeItem` to parse each individual element. + private mutating func takeItems( + from stream: inout Substring, + takingEachWith takeItem: (inout Self, inout Substring) -> T? + ) -> [T]? { + guard let n = takeInteger(from: &stream) else { return nil } + var xs: [T] = [] + xs.reserveCapacity(Int(n.rawValue)) + + for _ in 0 ..< n.rawValue { + guard let x = takeItem(&self, &stream) else { return nil } + xs.append(x) + } + return xs + } + } From 55c082136d1dddbf2fa1ffaab2b2e248a0916fb8 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 30 Aug 2024 14:39:42 +0200 Subject: [PATCH 7/9] Compress repeated occurrences of a string in mangled symbols --- Sources/IR/Mangling/Demangler.swift | 25 +++++++++++++++++-------- Sources/IR/Mangling/Mangler.swift | 23 +++++++++++++++++++---- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Sources/IR/Mangling/Demangler.swift b/Sources/IR/Mangling/Demangler.swift index 410d39619..47a4a44c8 100644 --- a/Sources/IR/Mangling/Demangler.swift +++ b/Sources/IR/Mangling/Demangler.swift @@ -3,6 +3,9 @@ import FrontEnd /// Hylo's demangling algorithm. struct Demangler { + /// The list of demangled strings, in order of appearance (a.k.a. the string lookup table). + private var strings: [Substring] = [] + /// The list of demangled symbols, in order of appearance (a.k.a. the symbol lookup table). private var symbols: [DemangledSymbol] = [] @@ -608,7 +611,7 @@ struct Demangler { /// Assuming `stream` starts with a mangled name, consumes and returns it. Returns `nil` iff /// data seems corrupted - private func takeName(from stream: inout Substring) -> Name? { + private mutating func takeName(from stream: inout Substring) -> Name? { guard let tag = takeBase64Digit(from: &stream) else { return nil } @@ -638,15 +641,21 @@ struct Demangler { /// Assuming `stream` starts with a mangled string, consumes and returns it. Returns `nil` iff ///the data seems corrupted - private func takeString(from stream: inout Substring) -> Substring? { - guard let length = takeInteger(from: &stream) else { + private mutating func takeString(from stream: inout Substring) -> Substring? { + switch takeInteger(from: &stream)?.rawValue { + case .some(0): + return stream[stream.startIndex ..< stream.startIndex] + case .some(1): + return takeInteger(from: &stream).flatMap({ (m) in strings[Int(m.rawValue)] }) + case .some(let n): + let j = stream.index(stream.startIndex, offsetBy: Int(n - 2)) + let r = stream[..( _ s: T, manglingWith mangle: (inout Self, T, inout Output) -> Void ) -> Output { + var c = stringPosition var p = symbolPosition var q = qualification defer { + swap(&c, &stringPosition) swap(&p, &symbolPosition) swap(&q, &qualification) } @@ -650,7 +655,7 @@ struct Mangler { } /// Writes the mangled representation of `name` to `output`. - private func append(name: Name, to output: inout Output) { + private mutating func append(name: Name, to output: inout Output) { // Only encode notation and introducer; labels are encoded in types. var tag: UInt8 = 0 if name.notation != nil { tag = 1 } @@ -667,9 +672,19 @@ struct Mangler { } /// Writes `string` to `output`, prefixed by its length encoded as a variable-length integer. - private func append(string: T, to output: inout Output) { - append(integer: string.count, to: &output) - string.write(to: &output) + private mutating func append(string: T, to output: inout Output) { + let s = String(string) + + if s.isEmpty { + append(integer: 0, to: &output) + } else if let n = stringPosition[s] { + append(integer: 1, to: &output) + append(integer: n, to: &output) + } else { + append(integer: s.count + 2, to: &output) + string.write(to: &output) + stringPosition[s] = stringPosition.count + } } /// Writes `v` encoded as a variable-length integer to `output`. From d3751744f3cd7ecda2d35a17c7b6f44ad871f4b8 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 30 Aug 2024 14:43:36 +0200 Subject: [PATCH 8/9] Add a test for demangling monomorphized symbols --- Tests/ManglingTests/ManglingTests.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Tests/ManglingTests/ManglingTests.swift b/Tests/ManglingTests/ManglingTests.swift index 0c8c43187..b39603cdc 100644 --- a/Tests/ManglingTests/ManglingTests.swift +++ b/Tests/ManglingTests/ManglingTests.swift @@ -118,6 +118,16 @@ final class ManglingTests: XCTestCase { is: "any Hylo.Movable") } + func testMonomorphized() { + let m = + "mFxF0R0UfDynamicBufferA10sF06init1lTR736selfpT2bTa" + + "TK1Z2gTK1G8HeadergTK1G9ElementacapacitypT1aTR2Zqin" + + "itializing_header_withpT1lTgTrKG3E10pT2K4R7R7YVQOu" + + ".fZlTtT112lTtT215rT1K9dinit_headerrT1Ke10pT2tT215K" + + "9gpayload_headerK4R70R72K9tT13cKj" + XCTAssertNotNil(DemangledSymbol(m)) + } + } /// An AST visitation callback that collects mangled symbols, asserting that they are unique. From 26ee8831e02f936af610740bf09dcf036083a0b0 Mon Sep 17 00:00:00 2001 From: Dimi Racordon Date: Fri, 30 Aug 2024 15:07:25 +0200 Subject: [PATCH 9/9] Silence false typo reports in mangling tests --- .typos.toml | 3 +++ Tests/ManglingTests/MangledStrings.swift | 10 ++++++++++ Tests/ManglingTests/ManglingTests.swift | 8 +------- 3 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 Tests/ManglingTests/MangledStrings.swift diff --git a/.typos.toml b/.typos.toml index 77ae59d8d..238ad4fdf 100644 --- a/.typos.toml +++ b/.typos.toml @@ -1,3 +1,6 @@ [default.extend-words] inout = "inout" # Mutable projection keyword olt = "olt" # Abbreviation for "ordered less than" + +[files] +extend-exclude = ["Tests/ManglingTests/MangledStrings.swift"] diff --git a/Tests/ManglingTests/MangledStrings.swift b/Tests/ManglingTests/MangledStrings.swift new file mode 100644 index 000000000..795c4a4da --- /dev/null +++ b/Tests/ManglingTests/MangledStrings.swift @@ -0,0 +1,10 @@ +extension ManglingTests { + + static let inputCase = + "mFxF0R0UfDynamicBufferA10sF06init1lTR736selfpT2bTa" + + "TK1Z2gTK1G8HeadergTK1G9ElementacapacitypT1aTR2Zqin" + + "itializing_header_withpT1lTgTrKG3E10pT2K4R7R7YVQOu" + + ".fZlTtT112lTtT215rT1K9dinit_headerrT1Ke10pT2tT215K" + + "9gpayload_headerK4R70R72K9tT13cKj" + +} diff --git a/Tests/ManglingTests/ManglingTests.swift b/Tests/ManglingTests/ManglingTests.swift index b39603cdc..25cbaa37f 100644 --- a/Tests/ManglingTests/ManglingTests.swift +++ b/Tests/ManglingTests/ManglingTests.swift @@ -119,13 +119,7 @@ final class ManglingTests: XCTestCase { } func testMonomorphized() { - let m = - "mFxF0R0UfDynamicBufferA10sF06init1lTR736selfpT2bTa" + - "TK1Z2gTK1G8HeadergTK1G9ElementacapacitypT1aTR2Zqin" + - "itializing_header_withpT1lTgTrKG3E10pT2K4R7R7YVQOu" + - ".fZlTtT112lTtT215rT1K9dinit_headerrT1Ke10pT2tT215K" + - "9gpayload_headerK4R70R72K9tT13cKj" - XCTAssertNotNil(DemangledSymbol(m)) + XCTAssertNotNil(DemangledSymbol(Self.inputCase)) } }