diff --git a/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/IrProviderFactory.kt b/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/IrProviderFactory.kt index 827c5314c..643e6b4e4 100644 --- a/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/IrProviderFactory.kt +++ b/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/IrProviderFactory.kt @@ -16,10 +16,12 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.util.getSimpleFunction import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.isObject +import org.jetbrains.kotlin.ir.util.kotlinFqName import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.ir.util.properties import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.konan.isNative internal sealed class ProviderFactory : IrMetroFactory, IrBindingContainerCallable { /** @@ -142,6 +144,25 @@ internal sealed class ProviderFactory : IrMetroFactory, IrBindingContainerCallab val rawTypeKey = contextKey.typeKey.copy(qualifier = callableMetadata.annotations.qualifier) val typeKey = rawTypeKey.transformIfIntoMultibinding(callableMetadata.annotations) + if (mirrorFunction.isExternalParent && context.platform.isNative()) { + // Validate qualifiers due to https://github.com/ZacSweers/metro/issues/1556 + val createFunctionParams = + clazz.requireSimpleFunction(Symbols.StringNames.CREATE).owner.parameters().allParameters + for ((i, mirrorP) in + callableMetadata.mirrorFunction.parameters().allParameters.withIndex()) { + val createP = createFunctionParams[i] + if (createP.typeKey != mirrorP.typeKey) { + reportCompilerBug( + """ + Mirror/create function parameter type mismatch: ${mirrorP.typeKey} != ${createP.typeKey} + Source: ${callableMetadata.function.kotlinFqName.asString()} + """ + .trimIndent() + ) + } + } + } + return Metro( factoryClass = clazz, typeKey = typeKey, diff --git a/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/transformers/InjectConstructorTransformer.kt b/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/transformers/InjectConstructorTransformer.kt index 5fd39f7c9..480ae51f1 100644 --- a/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/transformers/InjectConstructorTransformer.kt +++ b/compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/transformers/InjectConstructorTransformer.kt @@ -64,6 +64,7 @@ import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.primaryConstructor import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.platform.konan.isNative internal class InjectConstructorTransformer( context: IrMetroContext, @@ -124,10 +125,35 @@ internal class InjectConstructorTransformer( ?: reportCompilerBug( "Expected nested class '$factoryClassName' not found in '${declaration.kotlinFqName}'." ) - val parameters = - factoryCls.requireSimpleFunction(Symbols.StringNames.MIRROR_FUNCTION).owner.parameters() + val mirrorFunction = + factoryCls.requireSimpleFunction(Symbols.StringNames.MIRROR_FUNCTION).owner + val parameters = mirrorFunction.parameters() + // Look up the injectable constructor for direct invocation optimization val externalTargetConstructor = targetConstructor() + + if (platform.isNative()) { + // Validate qualifiers due to https://github.com/ZacSweers/metro/issues/1556 + val createFunctionParams = + factoryCls + .requireSimpleFunction(Symbols.StringNames.CREATE) + .owner + .parameters() + .allParameters + for ((i, mirrorP) in parameters.allParameters.withIndex()) { + val createP = createFunctionParams[i] + if (createP.typeKey != mirrorP.typeKey) { + reportCompilerBug( + """ + Mirror/create function parameter type mismatch: ${mirrorP.typeKey} != ${createP.typeKey} + Source: ${externalTargetConstructor?.kotlinFqName ?: declaration.kotlinFqName} + """ + .trimIndent() + ) + } + } + } + val wrapper = ClassFactory.MetroFactory(factoryCls, parameters, externalTargetConstructor) // If it's from another module, we're done! // TODO this doesn't work as expected in KMP, where things compiled in common are seen