Questions about (function type) mangling

I have some questions about mangling, specifically about function type mangling.

Looking at Mangling.rst, I noticed that function types are mangled with one "kind" modifier:

// From Mangling.rst:
type ::= function-signature 'c'            // function type (escaping)
type ::= function-signature 'X' FUNCTION-KIND // special function type

FUNCTION-KIND ::= 'f'                      // @thin function type
FUNCTION-KIND ::= 'U'                      // uncurried function type (currently not used)
FUNCTION-KIND ::= 'K'                      // @auto_closure function type (noescape)
FUNCTION-KIND ::= 'B'                      // objc block function type
FUNCTION-KIND ::= 'L'                      // objc block function type (escaping) (DWARF only; otherwise use 'B')
FUNCTION-KIND ::= 'C'                      // C function pointer type
FUNCTION-KIND ::= 'A'                      // @auto_closure function type (escaping)
FUNCTION-KIND ::= 'E'                      // function type (noescape)

However, in practice, function types can have many modifiers. Some information about modifiers may be lost during mangling.

// The type of `f` has multiple modifiers.
func foo(_ f: @convention(c) @autoclosure () -> Void) -> Void {}
$ swiftc -emit-silgen mangle.swift
// foo(_:)
sil hidden [ossa] @$s6mangle3fooyyyyXCF : $@convention(thin) (@convention(c) @noescape () -> ()) -> () {
  ...
}
$ swift-demangle s6mangle3fooyyyyXCF
$s6mangle3fooyyyyXCF ---> mangle.foo(@convention(c) () -> ()) -> ()
// Lost information about `@noescape` and `@autoclosure`.

Questions:

  • What is the significance of type mangling? Is it used by tools like LLDB to show the types of variables when debugging?
  • Is it desirable/important to accurately mangle all modifiers for a function type? Mangling semantically-impactful modifiers seems more important than less impactful modifiers (e.g. @convention(c) may be heavier than @noescape).

Context: I started a patch to implement type mangling for @differentiable functions, and noticed that the current mangling scheme leads to an explosion of function type modifier combinations.

A more flexible scheme could encode multiple modifiers. Sketch:

// Old: modifier is coupled with function type.
// Some modifier information is lost.
      kind=ThinFunctionType
        kind=ArgumentTuple
          kind=Type
            kind=Structure
              kind=Module, text="Swift"
              kind=Identifier, text="Float"
        kind=ReturnType
          kind=Type
            kind=Structure
              kind=Module, text="Swift"
              kind=Identifier, text="Float"

// New: modifiers are in a separate list.
// Modifier list can be run-length encoded, possibly in a
// backwards-compatible way.
      kind=FunctionType
        kind=FunctionTypeModifiers
          kind=ThinFunction
          kind=EscapingFunction
          kind=DifferentiableFunction
        kind=ArgumentTuple
          kind=Type
            kind=Structure
              kind=Module, text="Swift"
              kind=Identifier, text="Float"
        kind=ReturnType
          kind=Type
            kind=Structure
              kind=Module, text="Swift"
              kind=Identifier, text="Float"

But I'm not sure about the use cases for mangling. If mangling modifiers isn't important, then I suppose there's no need for a more flexible scheme.

I'm not an expert, but there are a few things to remember.

  • Mangling must uniquely distinguish overloadable declarations in any ways they can be overloadable, since it's used for symbol names, indexing, and compact references to entities at runtime.

  • Mangling of existing decls must be stable across changes to other decls (library evolution) and changes to the compiler (ABI stability) when compiling with -enable-library-evolution. (Therefore you can't say "oh, this has no overloads, so I'm going to give it a simpler mangling. This comes up sometimes.)

  • Mangling is used by LLDB to describe types, but I forget how. :-/

Mangling is used to disambiguate overloads, to construct runtime metadata and to show types in lldb as you suggest.

Since @convention(c) functions do not have a context, escaping/noescape has no significance in the type system. However, not being able to express @convention(c) @autoclosure is a bug, albeit one that has no practical consequences. Perhaps we should not allow @convention(foo) @autoclosure at all. Do you mind filing a bug so that we can revisit this some day?

Thanks for the swift replies! The purpose of mangling makes sense.

Some concrete follow-up questions:

  • Is it worth pursuing a more flexible scheme for mangling a list of function type modifiers? And is it possible to do so in a backwards-compatible way? Please see my post above.
  • Regarding @differentiable functions: which @differentiable + @xxx modifier combinations would you recommend mangling in the current scheme?

Filed SR-11027! @convention(c) @autoclosure actually crashes today.