Share
Embed
Metro Under the Hood
Zac Sweers
May 21, 2026
Transcript
258 slides
-
SLIDES TODO link •Part 2 of "Navigating Dependency Injection with
Metro" •(Metro) compiler internals •Focus on "what" and "why" •Occasionally "how" a a a -
Recap @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Recap @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Recap @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Recap @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Recap @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Factories @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Factories @Inject class Repository(api: Api) { // Metro generates class
MetroFactory(api: Provider<Api>) : Factory<Repository> { } } -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } } -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } } val apiProvider = ... val repoProvider = Repository.MetroFactory.create(apiProvider) -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } } val apiProvider = ... val repoProvider = Repository.MetroFactory.create(apiProvider) val repo = repoProvider() -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } } val apiProvider = ... val repoProvider = Repository.MetroFactory.create(apiProvider) val repo = repoProvider() -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } } -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(@Named("authed") api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } } -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api = Api()) = Repository(api) } } -
Factories @Deprecated(HIDDEN) class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun
invoke() : Repository = newInstance(api()) companion object { @JvmStatic @JsStatic @HiddenFromObjC fun create(api: Provider<Api>) = MetroFactory(api) @JvmStatic @JsStatic @HiddenFromObjC fun newInstance(api: Api) = Repository(api) } } -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } fun mirrorFunction(api: Api) : Repository { return error(message = "Never called") } } -
Factories class MetroFactory(api: Provider<Api>) : Factory<Repository> { override fun invoke()
: Repository = newInstance(api()) companion object { fun create(api: Provider<Api>) = MetroFactory(api) fun newInstance(api: Api) = Repository(api) } @Named(name = "authed") @HiddenFromObjC fun mirrorFunction(@Named(name = "authed") api: Api) : Repository { return error(message = "Never called") } } -
Factories @Inject class Repository(api: Api) { // Metro generates class
MetroFactory(api: Provider<Api>) : Factory<Repository> { } } -
Factories @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Factories @DependencyGraph interface AppGraph { @Provides fun provideApi() : Api
= Api() // Metro generates class ProvideApiMetroFactory(instance: AppGraph) : Factory<Api> } -
Factories class ProvideApiMetroFactory(instance: AppGraph) : Factory<Api> { override fun invoke()
: Api = provideApi(instance) companion object { fun create(instance: AppGraph) : Factory<Api> = ProvideApiMetroFactory(instance) fun provideApi(instance: AppGraph) : Api = instance.provideApi() } fun mirrorFunction() : Api = error(message = "Never called") } -
Graphs @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } -
Binding Containers @BindingContainer object ApiBindings { @Provides fun provideApi() :
Api = Api() } @DependencyGraph( bindingContainers = [ApiBindings :: class] ) interface AppGraph { val repository: Repository } -
Binding Containers @Metadata( ... ) @BindingContainer object ApiBindings { @Provides
fun provideApi() : Api = Api() } -
Binding Containers @Metadata( ... ) @BindingContainer object ApiBindings { @Provides
fun provideApi() : Api = Api() } message DependencyGraphProto { bool is_graph = 1; repeated ProviderFactoryProto provider_factories = 2; repeated string accessor_callable_names = 3; repeated int32 multibinding_accessor_indices = 4; repeated string included_binding_containers = 5; } message ProviderFactoryProto { string class_id = 1; bool invisible = 2; bool is_object = 3; string callable_name = 4; string property_name = 5; string new_instance_name = 6; } -
Graphs @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Graphs @DependencyGraph interface AppGraph { // Metro generates class Impl
: AppGraph { override val val repository: Repository get() = Repository(provideApi()) } } -
Graphs @DependencyGraph(AppScope :: class) interface AppGraph { // Metro generates
class Impl : AppGraph { private val repositoryProvider = DoubleCheck.provider(ProvideApiMetroFactory.create(this)) override val val repository: Repository get() = Repository(repositoryProvider()) } } -
Graphs @DependencyGraph interface AppGraph { // Metro generates class Impl
: AppGraph { override val val repository: Repository get() = Repository( DoubleCheck.lazy(ProvideApiMetroFactory.create(this)) ) } } @Inject class Repository(api: Lazy<Api>) -
Graphs @DependencyGraph interface AppGraph { @DependencyGraph.Factory interface Factory { fun
create(api: Api) : AppGraph } } -
Graphs @DependencyGraph interface AppGraph { class Impl : AppGraph {
override val val repository: Repository get() = Repository( DoubleCheck.lazy(ProvideApiMetroFactory.create(this)) ) } } -
Graphs @DependencyGraph interface AppGraph { class Impl(api: Api) : AppGraph
{ override val val repository: Repository get() = Repository( DoubleCheck.lazy(InstanceFactory.create(api)) ) } } -
Graphs @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
@Binds @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() @Binds val RepositoryImpl.bind: Repository } interface Repository @Inject class RepositoryImpl(api: Api) : Repository -
@Binds @DependencyGraph interface AppGraph { class Impl : AppGraph {
override val val repository: Repository get() = Repository(provideApi()) } } -
@Binds @DependencyGraph interface AppGraph { class Impl : AppGraph {
override val val repository: Repository get() = RepositoryImpl(provideApi()) } } -
@Binds @DependencyGraph interface AppGraph { @Binds val RepositoryImpl.bind: Repository abstract
class BindsMirror private constructor() { @Binds abstract fun RepositoryImpl.bind() : Repository } } -
@Binds @DependencyGraph interface AppGraph { @Binds val RepositoryImpl.bind: Repository @Deprecated(HIDDEN)
abstract class BindsMirror private constructor() { @Binds abstract fun RepositoryImpl.bind() : Repository } } -
@Binds @DependencyGraph interface AppGraph { @Binds val RepositoryImpl.bind: Repository @Deprecated(HIDDEN)
@ComptimeOnly abstract class BindsMirror private constructor() { @Binds abstract fun RepositoryImpl.bind() : Repository } } -
@Binds @DependencyGraph interface AppGraph { @Binds val RepositoryImpl.bind: Repository @Deprecated(HIDDEN)
@ComptimeOnly abstract class BindsMirror private constructor() { @Binds @CallableMetadata( ... ) abstract fun RepositoryImpl.bind() : Repository } } -
@Binds @DependencyGraph interface AppGraph { @Binds val RepositoryImpl.bind: Repository @Deprecated(HIDDEN)
@ComptimeOnly abstract class BindsMirror private constructor() { @Binds @CallableMetadata( callableName = "<get - bind>", propertyName = "bind", startOffset = 78, endOffset = 113 ) abstract fun RepositoryImpl.bind() : Repository } -
@Binds @DependencyGraph interface AppGraph { @Binds val RepositoryImpl.bind: Repository @ComptimeOnly
get() = error("Never called") } -
@Binds @CallableMetadata( callableName = "provideApi", propertyName = "", startOffset =
101, endOffset = 149, newInstanceName = "provideApi" ) class ProvideApiMetroFactory : Factory<Api> { ... } @ComptimeOnly fun mirrorFunction() : Api { ... } -
Graphs @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Multibindings @DependencyGraph interface AppGraph { val ints: Set<Int> @Provides @IntoSet
fun provideOne() : Int = 1 @Provides @IntoSet fun provideTwo() : Int = 2 } -
Multibindings @DependencyGraph interface AppGraph { //... private val setOfInt: Set<Int>
get() = buildSet(2) { add(provideOne()) add(provideTwo()) } } -
Multibindings @DependencyGraph interface AppGraph { val ints: Set<Int> get() =
setOfInt //... private val setOfInt: Set<Int> get() = buildSet(2) { add(provideOne()) add(provideTwo()) } } -
Multibindings @DependencyGraph interface AppGraph { val ints: () -> Set<Int>
get() = setOfInt //... private val setOfInt: Set<Int> get() = buildSet(2) { add(provideOne()) add(provideTwo()) } } -
Multibindings @DependencyGraph interface AppGraph { val ints: () -> Set<Int>
get() = setOfIntProvider //... private val setOfIntProvider: () -> Set<Int> get() { val builder = SetFactory.builder<Int>(2, 0) builder.addProvider(ProvideTwoMetroFactory.create()) builder.addProvider(ProvideOneMetroFactory.create()) return builder.build() } } -
Multibindings @DependencyGraph interface AppGraph { val ints: () -> Set<Int>
get() = setOfIntProvider val scalarInts: Set<Int> //... private val setOfIntProvider: () -> Set<Int> get() { // ... } } -
Multibindings @DependencyGraph interface AppGraph { val ints: () -> Set<Int>
get() = setOfIntProvider val scalarInts: Set<Int> get() = setOfIntProvider() //... private val setOfIntProvider: () -> Set<Int> get() { // ... } } -
Multibindings @DependencyGraph interface AppGraph { val ints: Set<Int> @Provides @ElementsIntoSet
fun provideElements() : Set<Int> = setOf(1, 2) } -
Multibindings @DependencyGraph interface AppGraph { //... private val setOfInt: Set<Int>
get() { val elements = provideElements() return buildSet(elements.size) { addAll(elements) } } } -
Multibindings @DependencyGraph interface AppGraph { //... private val setOfInt: ()
-> Set<Int> get() { val builder = SetFactory.builder<Int>(0, collectionProviderSize = 1) builder.addCollectionProvider(ProvideElementsMetroFactory.create(this)) return builder.build() } } -
Multibindings @DependencyGraph interface AppGraph { val ints: Set<Int> @Provides @IntoSet
fun provideOne() : Int = 1 @Provides @IntoSet fun provideTwo() : Int = 2 } -
Multibindings @DependencyGraph interface AppGraph { val ints: Set<Int> @Provides @IntoSet
fun provideOne() : Int = 1 @Provides @IntoSet fun provideTwo() : Int = 2 } -
Multibindings @DependencyGraph interface AppGraph { val ints: Set<Int> @Provides @IntoSet
@MultibindingElement( bindingId = ... , elementId = ... ) fun provideOne() : Int = 1 @Provides @IntoSet @MultibindingElement( bindingId = ... , elementId = ... ) fun provideTwo() : Int = 2 } -
Multibindings @DependencyGraph interface AppGraph { val ints: Set<Int> @Provides @IntoSet
fun provideOne() : Int = 1 @Provides @IntoSet fun provideTwo() : Int = 2 } -
Multibindings @DependencyGraph interface AppGraph { val ints: Map<Int, Int> @Provides
@IntoMap @IntKey(1) fun provideOne() : Int = 1 @Provides @IntoMap @IntKey(2) fun provideTwo() : Int = 2 } -
Multibindings @DependencyGraph interface AppGraph { //... private val mapOfIntToInt: Map<Int,
Int> get() = buildMap(2) { put(2, provideTwo()) put(1, provideOne()) } } -
Multibindings @DependencyGraph interface AppGraph { //... private val mapOfIntToIntProvider: ()
-> Map<Int, Int> get() { val builder = MapFactory.builder<Int, Int>(2) builder.put(2, ProvideTwoFactory.create(this)) builder.put(1, ProvideOneFactory.create(this)) return builder.build() } } -
Multibindings @DependencyGraph interface AppGraph { val ints: Map<Int, () ->
Int> private val mapOfIntToIntProvider: Map<Int, () -> Int >> get() = buildMap(2) { put(2, ProvideTwoFactory.create(this)) put(1, ProvideOneFactory.create(this)) } } -
Multibindings @DependencyGraph interface AppGraph { val ints: () -> Map<Int,
() -> Int> private val mapOfIntToIntProvider: () -> Map<Int, Int> get() { val builder = MapProviderFactory.builder<Int, Int>(2) builder.put(2, ProvideTwoFactory.create(this)) builder.put(1, ProvideOneFactory.create(this)) return builder.build() } } -
Assisted Injection @AssistedInject class Repository(api: Api, @Assisted token: String) {
@AssistedFactory interface Factory { fun create(token: String) : Repository } } -
Assisted Injection @AssistedInject class Repository(api: Api, @Assisted token: String) {
} @AssistedFactory interface Factory { fun create(token: String) : Repository } -
Assisted Injection @AssistedInject class Repository(api: Api, @Assisted token: String) {
// Metro Generates class MetroFactory(api: Provider<Api>) { operator fun invoke(token: String) : Repository = newInstance(api(), token) companion object { fun create(api: Provider<Api>) : MetroFactory = MetroFactory(api) fun newInstance(api: Api, token: String) : Repository = Repository(api, token) } } } -
Assisted Injection @AssistedInject class Repository(api: Api, @Assisted token: String) {
// Metro Generates class MetroFactory(api: Provider<Api>) { operator fun invoke(token: String) : Repository = newInstance(api(), token) companion object { fun create(api: Provider<Api>) : MetroFactory = MetroFactory(api) fun newInstance(api: Api, token: String) : Repository = Repository(api, token) } } } -
Assisted Injection @AssistedFactory interface Factory { fun create(token: String) :
Repository // Metro Generates class Impl( private val delegateFactory: Repository.MetroFactory ) : Factory { override fun create(token: String) : Reposistory { return delegateFactory(token) } } } -
Graphs @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @AssistedInject class Repository(api: Api, @Assisted token: String) -
Graphs @DependencyGraph interface AppGraph { // ... class Impl :
AppGraph { override val val repositoryFactory: Repository.Factory get() = Repository.Factory.Impl.create( ... ) } } -
Graphs @DependencyGraph interface AppGraph { // ... class Impl :
AppGraph { override val val repositoryFactory: Repository.Factory get() = Repository.Factory.Impl.create( delegateFactory = Repository.MetroFactory.create( ... ) ) } } -
Graphs @DependencyGraph interface AppGraph { // ... class Impl :
AppGraph { override val val repositoryFactory: Repository.Factory get() = Repository.Factory.Impl.create( delegateFactory = Repository.MetroFactory.create( apiProvider = ProvideApiMetroFactory.create(this) ) ) } } -
Aggregation @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class RepositoryImpl(api: Api) : Repository -
Aggregation @DependencyGraph interface AppGraph { val repository: Repository } @BindingContainer
object ApiBindings { @Provides fun provideApi() : Api = Api() } @Inject class RepositoryImpl(api: Api) : Repository -
Aggregation @DependencyGraph(AppScope :: class) interface AppGraph { val repository: Repository
} @BindingContainer @ContributesTo(AppScope :: class) object ApiBindings { @Provides fun provideApi() : Api = Api() } @ContributesBinding(AppScope :: class) @Inject class RepositoryImpl(api: Api) : Repository -
Aggregation @BindingContainer @ContributesTo(AppScope :: class) object ApiBindings @ContributesBinding(AppScope :: class)
@Inject class RepositoryImpl : Repository // FILE : repositoryImplAppScope.kt package metro.hints fun AppScope(contributed: RepositoryImpl) { return error(message = "Never called") } -
Aggregation @BindingContainer @ContributesTo(AppScope :: class) object ApiBindings @ContributesBinding(AppScope :: class)
@Inject class RepositoryImpl : Repository // FILE : apiBindingsAppScope.kt package metro.hints fun AppScope(contributed: ApiBindings) { return error(message = "Never called") } // FILE : repositoryImplAppScope.kt package metro.hints fun AppScope(contributed: RepositoryImpl) { return error(message = "Never called") } -
Aggregation // FILE : apiBindingsAppScope.kt package metro.hints fun AppScope(contributed: ApiBindings)
{ return error(message = "Never called") } // FILE : repositoryImplAppScope.kt package metro.hints fun AppScope(contributed: RepositoryImpl) { return error(message = "Never called") } @DependencyGraph(AppScope :: class) interface AppGraph { val repository: Repository } -
Aggregation // FILE : apiBindingsAppScope.kt package metro.hints fun AppScope(contributed: ApiBindings)
{ return error(message = "Never called") } // FILE : repositoryImplAppScope.kt package metro.hints fun AppScope(contributed: RepositoryImpl) { return error(message = "Never called") } @DependencyGraph(AppScope :: class) interface AppGraph { val repository: Repository } -
Aggregation // FILE : apiBindingsAppScope.kt package metro.hints fun AppScope(contributed: ApiBindings)
{ return error(message = "Never called") } // FILE : repositoryImplAppScope.kt package metro.hints fun AppScope(contributed: RepositoryImpl) { return error(message = "Never called") } @DependencyGraph(AppScope :: class) interface AppGraph { val repository: Repository } -
Aggregation ApiBindings RepositoryImpl @DependencyGraph(AppScope :: class) interface AppGraph { val
repository: Repository } -
Graphs @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Graph Extensions @DependencyGraph interface AppGraph { val repository: Repository }
@GraphExtension interface LoggedInGraph { } -
Graph Extensions @DependencyGraph interface AppGraph { } @GraphExtension interface LoggedInGraph
{ val repository: Repository } -
Graph Extensions @DependencyGraph interface AppGraph { val loggedInGraph: LoggedInGraph }
@GraphExtension interface LoggedInGraph { val repository: Repository } -
Graph Extensions @DependencyGraph interface AppGraph { //... class Impl :
AppGraph { override val loggedInGraph: LoggedInGraph get() = //... } } @GraphExtension interface LoggedInGraph { val repository: Repository } -
Graph Extensions @DependencyGraph interface AppGraph { //... class Impl :
AppGraph { override val loggedInGraph: LoggedInGraph get() = //... } @DependencyGraph private class LoggedInGraphImpl(appGraph: AppGraph) : LoggedInGraph { override val repository: Repository } } -
Graph Extensions @DependencyGraph interface AppGraph { //... class Impl :
AppGraph { override val loggedInGraph: LoggedInGraph get() = LoggedInGraphImpl(this) } @DependencyGraph private class LoggedInGraphImpl(appGraph: AppGraph) : LoggedInGraph { override val repository: Repository } } -
Graph Extensions @DependencyGraph interface AppGraph { //... @DependencyGraph private class
LoggedInGraphImpl(appGraph: AppGraph.Impl) : LoggedInGraph { override val repository: Repository get() = Repository(appGraph.provideApi()) } } -
Graph Extensions @DependencyGraph interface AppGraph { class Impl : AppGraph
{ private val apiProvider = DoubleCheck.provider(ProvideApiMetroFactory.create(this)) // ... } @DependencyGraph private class LoggedInGraphImpl(appGraph: AppGraph.Impl) : LoggedInGraph { override val repository: Repository get() = Repository(appGraph.apiProvider()) } } -
Graphs @DependencyGraph interface AppGraph { val repository: Repository @Provides fun
provideApi() : Api = Api() } @Inject class Repository(api: Api) -
Compiler Pipeline binary f i les Frontend Backend FIR IR
Lowering Parse/PSI fi r2ir Source f i les -
FIR Declaration Generation @DependencyGraph interface AppGraph { val repository: Repository
@Provides fun provideApi() : Api = Api() } @Inject class Repository(api: Api) -
FIR @DependencyGraph interface AppGraph { // ... class Impl :
AppGraph class ProvideApiMetroFactory } @Inject class Repository(api: Api) { class MetroFactory(api: Provider<Api>) } Declaration Generation -
FIR @DependencyGraph interface AppGraph { // ... class Impl :
AppGraph class ProvideApiMetroFactory : Factory<Api> } @Inject class Repository(api: Api) { class MetroFactory(api: Provider<Api>) : Factory<Repository> } Supertype Generation Declaration Generation -
FIR @DependencyGraph interface AppGraph { // ... class Impl :
AppGraph class ProvideApiMetroFactory : Factory<Api> { companion object } } @Inject class Repository(api: Api) { class MetroFactory(api: Provider<Api>) : Factory<Repository> { companion object } } Supertype Generation Declaration Generation -
FIR @DependencyGraph(AppScope :: class) interface AppGraph { // ... class
Impl : AppGraph, ApiBindings.MetroContributionToAppScope, RepositoryImpl.MetroContributionToAppScope } @ContributesIntoSet(AppScope :: class) @Inject class RepositoryImpl { @MetroContribution(AppScope :: class) interface MetroContributionToAppScope { // ... } } Supertype Generation Declaration Generation -
Compiler Pipeline binary f i les Frontend Backend FIR IR
Lowering Parse/PSI fi r2ir Source f i les -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@DefaultBinding<FragmentCreator <*> > interface FragmentCreator<T : Fragment> -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@DefaultBinding<FragmentCreator <*> > interface FragmentCreator<T : Fragment> { // Generated in FIR abstract class DefaultBindingMirror } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@DefaultBinding<FragmentCreator <*> > interface FragmentCreator<T : Fragment> { // Generated in FIR abstract class DefaultBindingMirror { // Generated in IR abstract fun defaultBinding() : FragmentCreator <*> } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@ContributesIntoSet(AppScope :: class) @Inject class RepositoryImpl(api: Api) : Repository -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@ContributesIntoSet(AppScope :: class) @Inject class RepositoryImpl(api: Api) : Repository { // Generated in FIR @BindingContainer @MetroContribution(AppScope :: class) interface MetroContributionToAppScope } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@ContributesIntoSet(AppScope :: class) @Inject class RepositoryImpl(api: Api) : Repository { // Generated in FIR @BindingContainer @MetroContribution(AppScope :: class) interface MetroContributionToAppScope { // Generated in IR @IntoSet @Binds fun bindIntoSetAsRepository(instance: RepositoryIm : error(message = "Never called") } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
class MainActivity { @Inject lateinit var id: String } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
class MainActivity { @Inject lateinit var id: String // FIR class MetroMembersInjector : MembersInjector<MainActivity> { // FIR companion object } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
class MainActivity { @Inject lateinit var id: String // FIR class MetroMembersInjector : MembersInjector<MainActivity> { // IR private val id: Provider<String> = ... // FIR companion object { // IR fun injectId(@Assisted instance: MainActivity, id_: String) { instance.id = id } } } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@Inject class Repository(api: Api) { // FIR class MetroFactory : Factory<Repository> { // FIR override fun invoke() : Repository // FIR companion object } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@Inject class Repository(api: Api) { // FIR class MetroFactory : Factory<Repository> { // IR private val api = ... // FIR override fun invoke() : Repository { // IR return Repository(api()) } // FIR companion object { // IR fun create( ... ) = ... // IR fun newInstance( ... ) = ... } } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@AssistedInject class Repository(@Assisted id: String) { @AssistedFactory interface Factory { fun create(id: String) : Repository // FIR class Impl : Factory { override fun create(id) : Repository } } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
@AssistedInject class Repository(@Assisted id: String) { @AssistedFactory interface Factory { fun create(id: String) : Repository // FIR class Impl : Factory { private val delegate: Repository.MetroFactory = ... override fun create(id) : Repository = delegate(id) } } } -
IR DefaultBindingMirrorTransformer ContributionIrTransformer ContributionHintIrTransformer MembersInjectorTransformer InjectedClassTransformer AssistedFactoryTransformer BindingContainerTransformer CreateGraphTransformer AsContributionTransformer
val contributedType = appGraph.asContribution<ContributedType>() val contributedType: ContributedType = appGraph -
IR ContributionIrTransformer InjectedClassTransformer BindingContainerTransformer interface MetroGraphData { val contributionData: IrContributionData
val graphs: List<GraphToProcess> val syntheticGraphs: List<GraphToProcess> val allGraphs get() = graphs + syntheticGraphs } data class GraphToProcess( val declaration: IrClass, val dependencyGraphAnno: IrConstructorCall, val graphImpl: IrClass, val scopes: Set<ClassId>, ) -
IR ContributionIrTransformer InjectedClassTransformer BindingContainerTransformer interface MetroGraphData { val contributionData: IrContributionData
val graphs: List<GraphToProcess> val syntheticGraphs: List<GraphToProcess> val allGraphs get() = graphs + syntheticGraphs } data class GraphToProcess( val declaration: IrClass, val dependencyGraphAnno: IrConstructorCall, val graphImpl: IrClass, val scopes: Set<ClassId>, ) -
IR ContributionIrTransformer InjectedClassTransformer BindingContainerTransformer val scopes: Set<ClassId> = graphData.allGraphs.flatMapToSet {
it.scopes } // FILE : apiBindingsAppScope.kt package metro.hints fun AppScope(contributed: ApiBindings) { return error(message = "Never called") } // FILE : repositoryImplAppScope.kt package metro.hints fun AppScope(contributed: RepositoryImpl) { return error(message = "Never called") } -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings @DependencyGraph interface AppGraph : ApiBindings, RepositoryImpl.MetroContributionToAppScope -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings @DependencyGraph interface AppGraph : ApiBindings, RepositoryImpl.MetroContributionToAppScope -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings @DependencyGraph( bindingContainers = [ApiBindings :: class] ) interface AppGraph -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings @DependencyGraph( bindingContainers = [ApiBindings :: class] ) interface AppGraph @BindingContainer(includes = [NetworkBindings :: class]) object ApiBindings { //... } -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings @DependencyGraph interface AppGraph { val repository: Repository fun inject(app: MyApp) } -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings sealed interface IrBinding { val typeKey: IrTypeKey val scope: IrAnnotation? val dependencies: List<IrContextualTypeKey> // ... } -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings class ConstructorInjected class ObjectClass // @Provides class Provided // @Binds class Alias class AssistedFactory class BoundInstance // For default values class Absent // For @Includes class GraphDependency class Multibinding class MembersInjected class GraphExtension class GraphExtensionFactory // j.u.Optional interop, etc. class CustomWrapper -
IR Collect supertypes Process binding containers - Process transitive closure
Merge contributions Process declarations (accessor roots, etc) Build BindingGraph - Collect bindings sealed interface IrBinding { val typeKey: IrTypeKey val scope: IrAnnotation? val dependencies: List<IrContextualTypeKey> // ... } -
IR sealed interface IrBinding : BaseBinding<IrType, IrTypeKey, IrContextualTypeKey> class IrTypeKey
: BaseTypeKey<IrType, IrAnnotation, IrTypeKey> class IrContextualTypeKey : BaseContextualTypeKey<IrType, IrTypeKey, IrContextualTypeKey> -
IR interface TypeKey { val type: Type, val qualif i
er: Annotation? } -
IR interface ContextualTypeKey { val typeKey: TypeKey, val wrapper: WrapperType,
// Provider, Lazy, etc val hasDefault: Boolean, } -
IR interface Binding { val typeKey: TypeKey val scope: Annotation?
val dependencies: List<ContextualTypeKey> // ... } -
IR interface BindingGraph { val bindings: Map<TypeKey, Binding> fun seal(
... ) : GraphTopology } -
IR interface BindingGraph { val bindings: Map<TypeKey, Binding> fun seal(
... ) : GraphTopology } -
IR interface BindingGraph { val bindings: Map<TypeKey, Binding> fun seal(
... ) : GraphTopology } BindingLookup -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) } fun populateGraph(roots) { // BFS from roots val queue = ArrayDeque<Binding>() val visited = HashSet<TypeKey>() while (queue.isNotEmpty()) { val next = queue.removeFirst() // Skipping code // Visit dependencies } } BindingLookup -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) } fun populateGraph(roots) { // BFS from roots val queue = ArrayDeque<Binding>() val visited = HashSet<TypeKey>() while (queue.isNotEmpty()) { val next = queue.removeFirst() // Skipping code // Visit dependencies } } BindingLookup -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) } fun populateGraph(roots) { // BFS from roots val queue = ArrayDeque<Binding>() val visited = HashSet<TypeKey>() while (queue.isNotEmpty()) { val next = queue.removeFirst() // Skipping code // Visit dependencies } } BindingLookup -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) } fun populateGraph(roots) { // BFS from roots val queue = ArrayDeque<Binding>() val visited = HashSet<TypeKey>() while (queue.isNotEmpty()) { val next = queue.removeFirst() // Skipping code // Visit dependencies } } BindingLookup Absent(MissingKey) -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) } fun populateGraph(roots) { // BFS from roots val queue = ArrayDeque<Binding>() val visited = HashSet<TypeKey>() while (queue.isNotEmpty()) { val next = queue.removeFirst() // Skipping code // Visit dependencies } } BindingLookup -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) } -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) if (missingBindings.isNotEmpty()) { for (missing in missingBindings) { reportMissingBinding(missing) } } } -
IR fun reportMissingBinding(missing: TypeKey, bindingStack: BindingStack) { if (reported(missing)) return
val message = buildString { append( "[Metro/MissingBinding] Cannot f i nd ... " ) appendLine(bold(typeKey.render(short = false))) appendLine() appendBindingStack(bindingStack, short = false) } } -
IR fun reportMissingBinding(missing: TypeKey, bindingStack: BindingStack) { if (reported(missing)) return
val message = buildString { //... val (hints, similarBindings) = missingBindingHints(typeKey) if (hints.isNotEmpty()) { appendLine("(Hint)") hints.joinTo(this, separator = "\n\n") } if (similarBindings.isNotEmpty()) { appendLine("Similar bindings:") for (binding in similarBindings.values.map { " - $it" }.sorted()) { appendLine(binding) } } } } -
IR fun reportMissingBinding(missing: TypeKey, bindingStack: BindingStack) { if (reported(missing)) return
val message = buildString { //... val (hints, similarBindings) = missingBindingHints(typeKey) if (hints.isNotEmpty()) { appendLine("(Hint)") hints.joinTo(this, separator = "\n\n") } if (similarBindings.isNotEmpty()) { appendLine("Similar bindings:") for (binding in similarBindings.values.map { " - $it" }.sorted()) { appendLine(binding) } } } } -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val missingBindings = populateGraph(roots) } -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val fullAdjacency = buildFullAdjacency(bindings) metroSort(fullAdjacency, roots, ... ) } -
Tarjan Strongly Connected Components (SCCs) @DependencyGraph interface AppGraph { val
homePresenter: HomePresenter } @Inject class HomePresenter(repository: Repository, logger: Logger) @Inject class Repository(api: Api, logger: Logger) @Inject class Logger(clock: Clock) @Inject class Clock -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph On -
stack: SCCs emitted: N : -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: SCCs emitted: N : 0 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter SCCs emitted: N : 1 idx=1 low=1 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo SCCs emitted: N : 2 idx=1 low=1 idx=2 low=2 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo, Api SCCs emitted: N : 3 idx=1 low=1 idx=2 low=2 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo SCCs emitted: Api N : 3 idx=1 low=1 idx=2 low=2 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo SCCs emitted: Api N : 3 idx=1 low=1 idx=2 low=2 idx=3 low=3 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo, Logger SCCs emitted: Api N : 4 idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo, Logger, Clock SCCs emitted: Api N : 5 idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo, Logger SCCs emitted: Api, Clock N : 5 idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter, Repo SCCs emitted: Api, Clock, Logger N : 5 idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: HomePresenter SCCs emitted: Api, Clock, Logger, Repo N : 5 idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 -
HomePresenter Tarjan SCCs Repository Logger Api Clock AppGraph idx=0 low=0
On - stack: SCCs emitted: Api, Clock, Logger, Repo, HomePresenter N : 5 idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 -
Tarjan SCCs class Impl : AppGraph { private val apiProvider:
Provider<Api> = ... private val clockProvider: Provider<Clock> = ... private val loggerProvider: Provider<Logger> = ... private val repositoryProvider: Provider<Repository> = ... private val homePresenterProvider: Provider<HomePresenter> = ... } -
Tarjan SCCs HomePresenter Repository Logger Api Clock AppGraph idx=0 low=0
idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 On - stack: HomePresenter, Repo, Logger, Clock SCCs emitted: Api N : 4 -
Tarjan SCCs HomePresenter Repository Logger Api Clock AppGraph idx=0 low=0
idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=4 On - stack: HomePresenter, Repo, Logger, Clock SCCs emitted: Api N : 5 -
Tarjan SCCs HomePresenter Repository Logger Api Clock AppGraph idx=0 low=0
idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=3 On - stack: HomePresenter, Repo, Logger, Clock SCCs emitted: Api N : 5 -
Tarjan SCCs HomePresenter Repository Logger Api Clock AppGraph idx=0 low=0
idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=3 On - stack: HomePresenter, Repo SCCs emitted: Api, [Logger, Clock] N : 5 -
Tarjan SCCs HomePresenter Repository Logger Api Clock AppGraph idx=0 low=0
idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=3 On - stack: HomePresenter, Repo SCCs emitted: Api, [Logger, Clock] N : 5 Lazy<Logger> -
Tarjan SCCs HomePresenter Repository Logger Api Clock AppGraph idx=0 low=0
idx=1 low=1 idx=2 low=2 idx=3 low=3 idx=4 low=3 On - stack: HomePresenter, Repo SCCs emitted: Api, [Logger, Clock] N : 5 Lazy<Logger> Deferred types: Clock -
Tarjan SCCs class Impl : AppGraph { private val apiProvider:
Provider<Api> = ... private val clockProvider: DelegateFactory<Clock> = ... private val loggerProvider: Provider<Logger> = ... private val repositoryProvider: Provider<Repository> = ... private val homePresenterProvider: Provider<HomePresenter> = ... } -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val fullAdjacency = buildFullAdjacency(bindings) metroSort(fullAdjacency, roots, ... ) } -
IR fun seal( roots: Map<ContextualTypeKey, BindingStackEntry> ) : GraphTopology {
val fullAdjacency = buildFullAdjacency(bindings) val topology = metroSort(fullAdjacency, roots, ... ) return topology } -
IR data class GraphTopology<T>( val sortedKeys: List<T>, val deferredTypes: Set<T>,
val reachableKeys: Set<T>, // ... ) -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
Api Clock Logger Repo HomePresenter -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
Api Clock Logger Repo HomePresenter BindingPropertyCollector -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
class Impl : HumongousAppGraph { // HUNDREDS of f i elds !! } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
IrGraphShardGenerator class Impl : HumongousAppGraph { val shard1 = Shard1(this) val shard2 = Shard2(this) class Shard1(parent: Impl) { // Dozens of f i elds } class Shard2(parent: Impl) { // Dozens of f i elds } } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
@DependencyGraph interface AppGraph { val homePresenter: HomePresenter } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
class Impl : AppGraph { } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
class Impl : AppGraph { val apiProvider = DoubleCheck.provider(Api.MetroFactory.create()) val clockProvider = DoubleCheck.provider(Clock.MetroFactory.create()) val loggerProvider = DoubleCheck.provider(Logger.MetroFactory.create(clockProvider)) } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
class Impl : AppGraph { val apiProvider = DoubleCheck.provider(Api.MetroFactory.create()) val clockProvider = DelegateFactory.create<Clock>() val loggerProvider = DoubleCheck.provider(Logger.MetroFactory.create(clockProvider)) init { clockProvider.setDelegate( DoubleCheck.provider(Clock.MetroFactory.create(loggerProvider))) } } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
class Impl : AppGraph { val apiProvider = ... val clockProvider = ... val loggerProvider = ... override val homePresenter: HomePresenter get() = } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
class Impl : AppGraph { val apiProvider = ... val clockProvider = ... val loggerProvider = ... override val homePresenter: HomePresenter get() = HomePresenter( Repository(apiProvider(), loggerProvider()) ) } -
IR 1. Collect properties 2. Collect shards 3. Implement accessors
class Impl : AppGraph { val shard1 = Shard1(this) val shard2 = Shard2(this) override val homePresenter: HomePresenter get() = HomePresenter( Repository(shard1.apiProvider(), shard2.loggerProvider()) ) } -
SwitchingProviders class Impl : AppGraph { val clockProvider = DoubleCheck.provider(Clock.MetroFactory.create())
val loggerProvider = DoubleCheck.provider(Logger.MetroFactory.create(clockProvider)) override val logger: Logger get() = loggerProvider() } -
SwitchingProviders class Impl : AppGraph { val clockProvider = DoubleCheck.provider(SwitchingProvider(1))
val loggerProvider = DoubleCheck.provider(SwitchingProvider(0)) //... private class SwitchingProvider<T>(graph: Impl, id: Int) : Provider<T> { override fun invoke() : T { return when (id) { 1 -> Clock() 0 -> Logger(graph.clockProvider()) } } } } -
Dynamic Graphs @DependencyGraph interface AppGraph { val value: String }
@BindingContainer class TestBindings { @Provides fun provideTestString() : String = "test" } // FILE : test.kt fun example() { val graph = createDynamicGraph<AppGraph>( TestBindings() ) assertEquals("test", graph.value) } -
Dynamic Graphs // FILE : test.kt fun example() { val
graph = createDynamicGraph<AppGraph>( TestBindings() ) assertEquals("test", graph.value) } class DynamicAppGraphImpl_s058e : AppGraph { // ... } -
Dynamic Graphs // FILE : test.kt fun example() { val
graph = DynamicAppGraphImpl_s058e(TestBindings()) assertEquals("test", graph.value) } class DynamicAppGraphImpl_s058e : AppGraph { // ... } -
Compat interface CompatContext { fun IrBuilder.irAnnotationCompat( callee: IrConstructorSymbol, typeArguments: List<IrType>,
) : IrConstructorCall // Bunch of others } -
Compat interface CompatContext { fun IrBuilder.irAnnotationCompat( callee: IrConstructorSymbol, typeArguments: List<IrType>,
) : IrConstructorCall // Bunch of others }