diff --git a/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcIrContext.kt b/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcIrContext.kt index 4edd1d3ea..84fc4d4c1 100644 --- a/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcIrContext.kt +++ b/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcIrContext.kt @@ -255,8 +255,8 @@ internal class RpcIrContext( grpcServiceDescriptor.namedFunction("delegate") } - val grpcMessageCodecResolverResolve by lazy { - grpcMessageCodecResolver.namedFunction("resolve") + val grpcMessageCodecResolverResolveOrNull by lazy { + grpcMessageCodecResolver.namedFunction("resolveOrNull") } private fun IrClassSymbol.namedFunction(name: String): IrSimpleFunction { diff --git a/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcStubGenerator.kt b/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcStubGenerator.kt index 515c2d623..da1c1876b 100644 --- a/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcStubGenerator.kt +++ b/compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/extension/RpcStubGenerator.kt @@ -1155,11 +1155,11 @@ internal class RpcStubGenerator( "Only methods are allowed here" } - check(callable.arguments.size == 1) { - "Only single argument methods are allowed here" + check(callable.arguments.size <= 1) { + "Only single or none argument methods are allowed here" } - val requestParameterType = callable.arguments[0].type + val requestParameterType = callable.arguments.getOrNull(0)?.type ?: ctx.irBuiltIns.unitType val responseParameterType = callable.function.returnType val requestType: IrType = requestParameterType.unwrapFlow() @@ -1262,7 +1262,7 @@ internal class RpcStubGenerator( startOffset = UNDEFINED_OFFSET, endOffset = UNDEFINED_OFFSET, type = ctx.grpcMessageCodec.typeWith(type), - symbol = ctx.functions.grpcMessageCodecResolverResolve.symbol, + symbol = ctx.functions.grpcMessageCodecResolverResolveOrNull.symbol, typeArgumentsCount = 0, valueArgumentsCount = 1, ) diff --git a/compiler-plugin/compiler-plugin-common/src/main/kotlin/kotlinx/rpc/codegen/common/Names.kt b/compiler-plugin/compiler-plugin-common/src/main/kotlin/kotlinx/rpc/codegen/common/Names.kt index d8e992075..a5c0d97c8 100644 --- a/compiler-plugin/compiler-plugin-common/src/main/kotlin/kotlinx/rpc/codegen/common/Names.kt +++ b/compiler-plugin/compiler-plugin-common/src/main/kotlin/kotlinx/rpc/codegen/common/Names.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.name.Name object RpcClassId { val rpcAnnotation = ClassId(FqName("kotlinx.rpc.annotations"), Name.identifier("Rpc")) val grpcAnnotation = ClassId(FqName("kotlinx.rpc.grpc.annotations"), Name.identifier("Grpc")) + val withCodecAnnotation = ClassId(FqName("kotlinx.rpc.grpc.codec"), Name.identifier("WithCodec")) val checkedTypeAnnotation = ClassId(FqName("kotlinx.rpc.annotations"), Name.identifier("CheckedTypeAnnotation")) val serializableAnnotation = ClassId(FqName("kotlinx.serialization"), Name.identifier("Serializable")) @@ -19,6 +20,8 @@ object RpcClassId { val flow = ClassId(FqName("kotlinx.coroutines.flow"), Name.identifier("Flow")) val sharedFlow = ClassId(FqName("kotlinx.coroutines.flow"), Name.identifier("SharedFlow")) val stateFlow = ClassId(FqName("kotlinx.coroutines.flow"), Name.identifier("StateFlow")) + + val messageCodec = ClassId(FqName("kotlinx.rpc.grpc.codec"), Name.identifier("MessageCodec")) } object RpcNames { diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcAdditionalCheckers.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcAdditionalCheckers.kt index fce3e3c2c..f684bbe02 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcAdditionalCheckers.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcAdditionalCheckers.kt @@ -23,6 +23,8 @@ class FirRpcAdditionalCheckers( ) : FirAdditionalCheckersExtension(session) { override fun FirDeclarationPredicateRegistrar.registerPredicates() { register(FirRpcPredicates.rpc) + register(FirRpcPredicates.grpc) + register(FirRpcPredicates.withCodec) register(FirRpcPredicates.checkedAnnotationMeta) } diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcPredicates.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcPredicates.kt index 53da7d569..967a927cb 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcPredicates.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirRpcPredicates.kt @@ -12,6 +12,14 @@ object FirRpcPredicates { metaAnnotated(RpcClassId.rpcAnnotation.asSingleFqName(), includeItself = true) // @Rpc } + internal val grpc = DeclarationPredicate.create { + metaAnnotated(RpcClassId.grpcAnnotation.asSingleFqName(), includeItself = true) + } + + internal val withCodec = DeclarationPredicate.create { + annotated(RpcClassId.withCodecAnnotation.asSingleFqName()) + } + internal val checkedAnnotationMeta = DeclarationPredicate.create { metaAnnotated(RpcClassId.checkedTypeAnnotation.asSingleFqName(), includeItself = false) } diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirGrpcServiceDeclarationChecker.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirGrpcServiceDeclarationChecker.kt new file mode 100644 index 000000000..675837715 --- /dev/null +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirGrpcServiceDeclarationChecker.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.codegen.checkers + +import kotlinx.rpc.codegen.FirRpcPredicates +import kotlinx.rpc.codegen.checkers.diagnostics.FirGrpcDiagnostics +import kotlinx.rpc.codegen.checkers.util.functionParametersRecursionCheck +import kotlinx.rpc.codegen.common.RpcClassId +import kotlinx.rpc.codegen.vsApi +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.types.isMarkedNullable + +object FirGrpcServiceDeclarationChecker { + fun check( + declaration: FirRegularClass, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { + if (!context.session.predicateBasedProvider.matches(FirRpcPredicates.grpc, declaration)) { + return + } + + vsApi { + declaration + .declarationsVS(context.session) + .filterIsInstance() + }.onEach { function -> + if (function.valueParameterSymbols.size > 1) { + reporter.reportOn( + source = function.source, + factory = FirGrpcDiagnostics.MULTIPLE_PARAMETERS_IN_GRPC_SERVICE, + context = context, + ) + } + + if (function.valueParameterSymbols.size == 1) { + val parameterSymbol = function.valueParameterSymbols[0] + if (parameterSymbol.resolvedReturnType.isMarkedNullable) { + reporter.reportOn( + source = parameterSymbol.source, + factory = FirGrpcDiagnostics.NULLABLE_PARAMETER_IN_GRPC_SERVICE, + context = context, + ) + } + + functionParametersRecursionCheck( + function = function, + context = context, + ) { source, symbol, parents -> + if (symbol.classId == RpcClassId.flow && parents.isNotEmpty()) { + reporter.reportOn( + source = source, + factory = FirGrpcDiagnostics.NON_TOP_LEVEL_CLIENT_STREAMING_IN_RPC_SERVICE, + context = context, + ) + } + } + } + + if (function.resolvedReturnType.isMarkedNullable) { + reporter.reportOn( + source = function.resolvedReturnTypeRef.source, + factory = FirGrpcDiagnostics.NULLABLE_RETURN_TYPE_IN_GRPC_SERVICE, + context = context, + ) + } + } + } +} diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcCheckers.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcCheckers.kt index 6b66f90d3..21d248141 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcCheckers.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcCheckers.kt @@ -18,6 +18,8 @@ class FirRpcDeclarationCheckers(ctx: FirCheckersContext) : DeclarationCheckers() FirRpcAnnotationCheckerVS(), FirRpcStrictModeClassCheckerVS(), FirRpcServiceDeclarationCheckerVS(ctx), + FirGrpcServiceDeclarationCheckerVS(), + FirWithCodecDeclarationCheckerVS(), ) override val classCheckers: Set = setOf( diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcStrictModeClassChecker.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcStrictModeClassChecker.kt index b4c858ab8..a9bb88cad 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcStrictModeClassChecker.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirRpcStrictModeClassChecker.kt @@ -6,6 +6,7 @@ package kotlinx.rpc.codegen.checkers import kotlinx.rpc.codegen.FirRpcPredicates import kotlinx.rpc.codegen.checkers.diagnostics.FirRpcStrictModeDiagnostics +import kotlinx.rpc.codegen.checkers.util.functionParametersRecursionCheck import kotlinx.rpc.codegen.common.RpcClassId import kotlinx.rpc.codegen.vsApi import org.jetbrains.kotlin.KtSourceElement @@ -13,19 +14,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0 import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.fir.analysis.checkers.extractArgumentsTypeRefAndSource -import org.jetbrains.kotlin.fir.analysis.checkers.toClassLikeSymbol import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider -import org.jetbrains.kotlin.fir.scopes.impl.toConeType -import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol -import org.jetbrains.kotlin.fir.types.FirTypeRef -import org.jetbrains.kotlin.utils.memoryOptimizedMap -import org.jetbrains.kotlin.utils.memoryOptimizedPlus object FirRpcStrictModeClassChecker { fun check( @@ -37,7 +30,6 @@ object FirRpcStrictModeClassChecker { return } - val serializablePropertiesProvider = context.session.serializablePropertiesProvider vsApi { declaration.declarationsVS(context.session) }.forEach { declaration -> when (declaration) { is FirPropertySymbol -> { @@ -45,116 +37,44 @@ object FirRpcStrictModeClassChecker { } is FirNamedFunctionSymbol -> { - checkFunction(declaration, context, reporter, serializablePropertiesProvider) - } - - else -> {} - } - } - } - - private fun checkFunction( - function: FirNamedFunctionSymbol, - context: CheckerContext, - reporter: DiagnosticReporter, - serializablePropertiesProvider: FirSerializablePropertiesProvider, - ) { - fun reportOn(element: KtSourceElement?, checker: FirRpcStrictModeDiagnostics.() -> KtDiagnosticFactory0?) { - reporter.reportOn(element, FirRpcStrictModeDiagnostics.checker() ?: return, context) - } - - val returnClassSymbol = vsApi { - function.resolvedReturnTypeRef.coneTypeVS.toClassSymbolVS(context.session) - } - - val types = function.valueParameterSymbols.memoryOptimizedMap { parameter -> - parameter.source to vsApi { - parameter.resolvedReturnTypeRef - } - } memoryOptimizedPlus (function.resolvedReturnTypeRef.source to function.resolvedReturnTypeRef) + fun reportOn(element: KtSourceElement?, checker: FirRpcStrictModeDiagnostics.() -> KtDiagnosticFactory0) { + reporter.reportOn(element, FirRpcStrictModeDiagnostics.checker(), context) + } - types.forEach { (source, symbol) -> - checkSerializableTypes( - context = context, - typeRef = symbol, - serializablePropertiesProvider = serializablePropertiesProvider, - ) { symbol, parents -> - when (symbol.classId) { - RpcClassId.stateFlow -> { - reportOn(source) { STATE_FLOW_IN_RPC_SERVICE } + val returnClassSymbol = vsApi { + declaration.resolvedReturnTypeRef.coneTypeVS.toClassSymbolVS(context.session) } - RpcClassId.sharedFlow -> { - reportOn(source) { SHARED_FLOW_IN_RPC_SERVICE } + if (returnClassSymbol?.classId == RpcClassId.flow && declaration.isSuspend) { + reportOn(declaration.source) { SUSPENDING_SERVER_STREAMING_IN_RPC_SERVICE } } - RpcClassId.flow -> { - if (parents.any { it.classId == RpcClassId.flow }) { - reportOn(source) { NESTED_STREAMING_IN_RPC_SERVICE } - } else if (parents.isNotEmpty() && parents[0] == returnClassSymbol) { - reportOn(source) { NON_TOP_LEVEL_SERVER_STREAMING_IN_RPC_SERVICE } + functionParametersRecursionCheck( + function = declaration, + context = context, + ) { source, symbol, parents -> + when (symbol.classId) { + RpcClassId.stateFlow -> { + reportOn(source) { STATE_FLOW_IN_RPC_SERVICE } + } + + RpcClassId.sharedFlow -> { + reportOn(source) { SHARED_FLOW_IN_RPC_SERVICE } + } + + RpcClassId.flow -> { + if (parents.any { it.classId == RpcClassId.flow }) { + reportOn(source) { NESTED_STREAMING_IN_RPC_SERVICE } + } else if (parents.isNotEmpty() && parents[0] == returnClassSymbol) { + reportOn(source) { NON_TOP_LEVEL_SERVER_STREAMING_IN_RPC_SERVICE } + } + } } } } - } - } - if (returnClassSymbol?.classId == RpcClassId.flow && function.isSuspend) { - reportOn(function.source) { SUSPENDING_SERVER_STREAMING_IN_RPC_SERVICE } - } - } - - private fun checkSerializableTypes( - context: CheckerContext, - typeRef: FirTypeRef, - serializablePropertiesProvider: FirSerializablePropertiesProvider, - parentContext: List> = emptyList(), - checker: (FirClassLikeSymbol<*>, List>) -> Unit, - ) { - val symbol = typeRef.toClassLikeSymbol(context.session) ?: return - - checker(symbol, parentContext) - - if (symbol !is FirClassSymbol<*>) { - return - } - - val nextContext = parentContext memoryOptimizedPlus symbol - - if (symbol in parentContext && symbol.typeParameterSymbols.isEmpty()) { - return - } - - val typeParameters = extractArgumentsTypeRefAndSource(typeRef) - .orEmpty() - .withIndex() - .associate { (i, refSource) -> - symbol.typeParameterSymbols[i].toConeType() to refSource.typeRef + else -> {} } - - val flowProps: List = if (symbol.classId == RpcClassId.flow) { - listOf(typeParameters.values.toList()[0]!!) - } else { - emptyList() } - - serializablePropertiesProvider.getSerializablePropertiesForClass(symbol) - .mapNotNull { property -> - val resolvedTypeRef = property.resolvedReturnTypeRef - if (resolvedTypeRef.toClassLikeSymbol(context.session) != null) { - resolvedTypeRef - } else { - typeParameters[property.resolvedReturnType] - } - }.memoryOptimizedPlus(flowProps) - .forEach { symbol -> - checkSerializableTypes( - context = context, - typeRef = symbol, - serializablePropertiesProvider = serializablePropertiesProvider, - parentContext = nextContext, - checker = checker, - ) - } } } diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt new file mode 100644 index 000000000..d587fc161 --- /dev/null +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.codegen.checkers + +import kotlinx.rpc.codegen.FirRpcPredicates +import kotlinx.rpc.codegen.FirVersionSpecificApiImpl.toClassSymbolVS +import kotlinx.rpc.codegen.checkers.diagnostics.FirGrpcDiagnostics +import kotlinx.rpc.codegen.common.RpcClassId +import kotlinx.rpc.codegen.vsApi +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.findArgumentByName +import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId +import org.jetbrains.kotlin.fir.declarations.getKClassArgument +import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider +import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.classId +import org.jetbrains.kotlin.fir.types.type +import org.jetbrains.kotlin.name.Name + +object FirWithCodecDeclarationChecker { + fun check( + declaration: FirRegularClass, + context: CheckerContext, + reporter: DiagnosticReporter, + ) { + if (!context.session.predicateBasedProvider.matches(FirRpcPredicates.withCodec, declaration)) { + return + } + + val withCodec = declaration.getAnnotationByClassId(RpcClassId.withCodecAnnotation, context.session) + ?: error( + "Unexpected unresolved @WithCodec annotation type " + + "for declaration: ${declaration.symbol.classId.asSingleFqName()}" + ) + + val kClassValue = withCodec.getKClassArgument(CODEC_ARGUMENT_NAME, context.session) + ?: error( + "Unexpected unresolved 'codec' argument for @WithCodec annotation " + + "for declaration: ${declaration.symbol.classId.asSingleFqName()}" + ) + + val codecClassSymbol = vsApi { kClassValue.toClassSymbolVS(context.session) } + ?: error( + "'codec' argument type for @WithCodec annotation is not a class " + + "for declaration: ${declaration.symbol.classId.asSingleFqName()}" + ) + + val codecTargetClass = codecClassSymbol.findMessageCodecSuperType(context.session) + .typeArguments.first().type + + if (codecTargetClass?.classId != declaration.symbol.classId) { + reporter.reportOn( + source = withCodec.findArgumentByName(CODEC_ARGUMENT_NAME)?.source, + factory = FirGrpcDiagnostics.CODEC_TYPE_MISMATCH, + a = declaration.symbol.defaultType(), + b = kClassValue, + context = context, + ) + } + + if (codecClassSymbol.classKind != ClassKind.OBJECT) { + reporter.reportOn( + source = withCodec.findArgumentByName(CODEC_ARGUMENT_NAME)?.source, + factory = FirGrpcDiagnostics.NOT_AN_OBJECT_REFERENCE_IN_WITH_CODEC_ANNOTATION, + context = context, + ) + } + } + + private fun FirClassSymbol<*>.findMessageCodecSuperType(session: FirSession): ConeKotlinType = vsApi { + return resolvedSuperTypes.find { + it.classId == RpcClassId.messageCodec + } ?: resolvedSuperTypes.firstNotNullOf { + it.toClassSymbolVS(session)?.findMessageCodecSuperType(session) + } + } + + private val CODEC_ARGUMENT_NAME = Name.identifier("codec") +} diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/FirRpcDiagnostics.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/FirRpcDiagnostics.kt index 8d5897fea..cc015f758 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/FirRpcDiagnostics.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/FirRpcDiagnostics.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.diagnostics.error2 import org.jetbrains.kotlin.diagnostics.error3 import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotated @@ -50,3 +51,16 @@ object FirRpcStrictModeDiagnostics : RpcKtDiagnosticsContainer() { return RpcStrictModeDiagnosticRendererFactory } } + +object FirGrpcDiagnostics : RpcKtDiagnosticsContainer() { + val NULLABLE_PARAMETER_IN_GRPC_SERVICE by error0() + val NULLABLE_RETURN_TYPE_IN_GRPC_SERVICE by error0() + val NON_TOP_LEVEL_CLIENT_STREAMING_IN_RPC_SERVICE by error0() + val MULTIPLE_PARAMETERS_IN_GRPC_SERVICE by error0() + val NOT_AN_OBJECT_REFERENCE_IN_WITH_CODEC_ANNOTATION by error0() + val CODEC_TYPE_MISMATCH by error2() + + override fun getRendererFactoryVs(): BaseDiagnosticRendererFactory { + return GrpcDiagnosticRendererFactory + } +} diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/RpcDiagnosticRendererFactory.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/RpcDiagnosticRendererFactory.kt index e1bc0e34c..34724c89b 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/RpcDiagnosticRendererFactory.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/diagnostics/RpcDiagnosticRendererFactory.kt @@ -100,3 +100,39 @@ object RpcStrictModeDiagnosticRendererFactory : BaseDiagnosticRendererFactory() "Support will be removed completely in the 0.8.0 release." } } + +object GrpcDiagnosticRendererFactory : BaseDiagnosticRendererFactory() { + override val MAP by RpcKtDiagnosticFactoryToRendererMap("Grpc") { map -> + map.put( + factory = FirGrpcDiagnostics.NULLABLE_PARAMETER_IN_GRPC_SERVICE, + message = "Nullable type is not allowed in @Grpc service function parameters.", + ) + + map.put( + factory = FirGrpcDiagnostics.NULLABLE_RETURN_TYPE_IN_GRPC_SERVICE, + message = "Nullable type is not allowed in @Grpc service function return types.", + ) + + map.put( + factory = FirGrpcDiagnostics.NON_TOP_LEVEL_CLIENT_STREAMING_IN_RPC_SERVICE, + message = "Non top-level client-side streaming is not allowed in @Grpc services.", + ) + + map.put( + factory = FirGrpcDiagnostics.MULTIPLE_PARAMETERS_IN_GRPC_SERVICE, + message = "Multiple parameters are not allowed in @Grpc service functions.", + ) + + map.put( + factory = FirGrpcDiagnostics.NOT_AN_OBJECT_REFERENCE_IN_WITH_CODEC_ANNOTATION, + message = "'codec' parameter must reference an object, not a class or an interface.", + ) + + map.put( + factory = FirGrpcDiagnostics.CODEC_TYPE_MISMATCH, + message = "Codec type mismatch. Expected {0}, got {1}.", + rendererA = FirDiagnosticRenderers.RENDER_TYPE, + rendererB = FirDiagnosticRenderers.RENDER_TYPE, + ) + } +} diff --git a/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/util/functionParametersRecursionCheck.kt b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/util/functionParametersRecursionCheck.kt new file mode 100644 index 000000000..d1e1eadad --- /dev/null +++ b/compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/util/functionParametersRecursionCheck.kt @@ -0,0 +1,99 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.codegen.checkers.util + +import kotlinx.rpc.codegen.checkers.FirSerializablePropertiesProvider +import kotlinx.rpc.codegen.checkers.serializablePropertiesProvider +import kotlinx.rpc.codegen.common.RpcClassId +import kotlinx.rpc.codegen.vsApi +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.extractArgumentsTypeRefAndSource +import org.jetbrains.kotlin.fir.analysis.checkers.toClassLikeSymbol +import org.jetbrains.kotlin.fir.scopes.impl.toConeType +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.utils.memoryOptimizedMap +import org.jetbrains.kotlin.utils.memoryOptimizedPlus +import kotlin.collections.get +import kotlin.collections.orEmpty +import kotlin.collections.withIndex + +internal fun functionParametersRecursionCheck( + function: FirNamedFunctionSymbol, + context: CheckerContext, + checker: (KtSourceElement?, FirClassLikeSymbol<*>, List>) -> Unit, +) { + val types = function.valueParameterSymbols.memoryOptimizedMap { parameter -> + parameter.source to vsApi { + parameter.resolvedReturnTypeRef + } + } memoryOptimizedPlus (function.resolvedReturnTypeRef.source to function.resolvedReturnTypeRef) + + types.forEach { (source, symbol) -> + checkSerializableTypes( + context = context, + typeRef = symbol, + serializablePropertiesProvider = context.session.serializablePropertiesProvider, + checker = { classSymbol, parentContext -> checker(source, classSymbol, parentContext) }, + ) + } +} + +private fun checkSerializableTypes( + context: CheckerContext, + typeRef: FirTypeRef, + serializablePropertiesProvider: FirSerializablePropertiesProvider, + parentContext: List> = emptyList(), + checker: (FirClassLikeSymbol<*>, List>) -> Unit, +) { + val symbol = typeRef.toClassLikeSymbol(context.session) ?: return + + checker(symbol, parentContext) + + if (symbol !is FirClassSymbol<*>) { + return + } + + val nextContext = parentContext memoryOptimizedPlus symbol + + if (symbol in parentContext && symbol.typeParameterSymbols.isEmpty()) { + return + } + + val typeParameters = extractArgumentsTypeRefAndSource(typeRef) + .orEmpty() + .withIndex() + .associate { (i, refSource) -> + symbol.typeParameterSymbols[i].toConeType() to refSource.typeRef + } + + val flowProps: List = if (symbol.classId == RpcClassId.flow) { + listOf(typeParameters.values.toList()[0]!!) + } else { + emptyList() + } + + serializablePropertiesProvider.getSerializablePropertiesForClass(symbol) + .mapNotNull { property -> + val resolvedTypeRef = property.resolvedReturnTypeRef + if (resolvedTypeRef.toClassLikeSymbol(context.session) != null) { + resolvedTypeRef + } else { + typeParameters[property.resolvedReturnType] + } + }.memoryOptimizedPlus(flowProps) + .forEach { symbol -> + checkSerializableTypes( + context = context, + typeRef = symbol, + serializablePropertiesProvider = serializablePropertiesProvider, + parentContext = nextContext, + checker = checker, + ) + } +} diff --git a/compiler-plugin/compiler-plugin-k2/src/main/templates/kotlinx/rpc/codegen/checkers/FirRpcCheckersVS.kt b/compiler-plugin/compiler-plugin-k2/src/main/templates/kotlinx/rpc/codegen/checkers/FirRpcCheckersVS.kt index 790d7110e..46fefd08f 100644 --- a/compiler-plugin/compiler-plugin-k2/src/main/templates/kotlinx/rpc/codegen/checkers/FirRpcCheckersVS.kt +++ b/compiler-plugin/compiler-plugin-k2/src/main/templates/kotlinx/rpc/codegen/checkers/FirRpcCheckersVS.kt @@ -140,3 +140,35 @@ class FirRpcStrictModeClassCheckerVS : FirRegularClassChecker(MppCheckerKind.Com //##csm /default //##csm /FirRpcStrictModeClassCheckerVS_context } + +class FirGrpcServiceDeclarationCheckerVS : FirRegularClassChecker(MppCheckerKind.Common) { + //##csm FirGrpcServiceDeclarationCheckerVS_context + //##csm specific=[2.0.0...2.1.21, 2.2.0-ij251-*] + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + FirGrpcServiceDeclarationChecker.check(declaration, context, reporter) + } + //##csm /specific + //##csm default + context(context: CheckerContext, reporter: DiagnosticReporter) + override fun check(declaration: FirRegularClass) { + FirGrpcServiceDeclarationChecker.check(declaration, context, reporter) + } + //##csm /default + //##csm /FirGrpcServiceDeclarationCheckerVS_context +} + +class FirWithCodecDeclarationCheckerVS : FirRegularClassChecker(MppCheckerKind.Common) { + //##csm FirWithCodecDeclarationChecker_context + //##csm specific=[2.0.0...2.1.21, 2.2.0-ij251-*] + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + FirWithCodecDeclarationChecker.check(declaration, context, reporter) + } + //##csm /specific + //##csm default + context(context: CheckerContext, reporter: DiagnosticReporter) + override fun check(declaration: FirRegularClass) { + FirWithCodecDeclarationChecker.check(declaration, context, reporter) + } + //##csm /default + //##csm /FirWithCodecDeclarationChecker_context +} diff --git a/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt b/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt index a14e44e28..a67dae17f 100644 --- a/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt +++ b/grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt @@ -17,12 +17,13 @@ import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialFormat import kotlinx.serialization.StringFormat import kotlinx.serialization.serializer +import kotlinx.serialization.serializerOrNull import kotlin.reflect.KType @ExperimentalRpcApi public class KotlinxSerializationCodecResolver(private val serialFormat: SerialFormat) : MessageCodecResolver { - override fun resolve(kType: KType): MessageCodec<*> { - val serializer = serialFormat.serializersModule.serializer(kType) + override fun resolveOrNull(kType: KType): MessageCodec<*>? { + val serializer = serialFormat.serializersModule.serializerOrNull(kType) ?: return null return KotlinxSerializationCodec(serializer, serialFormat) } diff --git a/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt b/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt index 93eca68a6..2ade94cab 100644 --- a/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt +++ b/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt @@ -6,17 +6,25 @@ package kotlinx.rpc.grpc.codec import kotlinx.io.Source import kotlinx.rpc.internal.utils.ExperimentalRpcApi +import kotlinx.rpc.internal.utils.InternalRpcApi import kotlin.reflect.KType @ExperimentalRpcApi public fun interface MessageCodecResolver { - public fun resolve(kType: KType): MessageCodec<*> + public fun resolveOrNull(kType: KType): MessageCodec<*>? } @ExperimentalRpcApi public object EmptyMessageCodecResolver : MessageCodecResolver { - override fun resolve(kType: KType): MessageCodec<*> { - error("No codec found for type $kType") + override fun resolveOrNull(kType: KType): MessageCodec<*>? { + return null + } +} + +@ExperimentalRpcApi +public operator fun MessageCodecResolver.plus(other: MessageCodecResolver): MessageCodecResolver { + return MessageCodecResolver { kType -> + this.resolveOrNull(kType) ?: other.resolveOrNull(kType) } } @@ -25,3 +33,10 @@ public interface MessageCodec { public fun encode(value: T): Source public fun decode(stream: Source): T } + +@InternalRpcApi +public object ThrowingMessageCodecResolver : MessageCodecResolver { + override fun resolveOrNull(kType: KType): MessageCodec<*> { + error("No codec found for type $kType") + } +} diff --git a/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/WithCodec.kt b/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/WithCodec.kt index 6de72bafa..4eaba2b7a 100644 --- a/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/WithCodec.kt +++ b/grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/WithCodec.kt @@ -8,4 +8,5 @@ import kotlinx.rpc.internal.utils.ExperimentalRpcApi import kotlin.reflect.KClass @ExperimentalRpcApi +@Target(AnnotationTarget.CLASS) public annotation class WithCodec(val codec: KClass>) diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt index ad37aaaed..32b891486 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcClient.kt @@ -9,6 +9,8 @@ import kotlinx.rpc.RpcCall import kotlinx.rpc.RpcClient import kotlinx.rpc.grpc.codec.EmptyMessageCodecResolver import kotlinx.rpc.grpc.codec.MessageCodecResolver +import kotlinx.rpc.grpc.codec.ThrowingMessageCodecResolver +import kotlinx.rpc.grpc.codec.plus import kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate import kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor import kotlinx.rpc.grpc.internal.* @@ -24,9 +26,10 @@ private typealias RequestClient = Any */ public class GrpcClient internal constructor( private val channel: ManagedChannel, - private val messageCodecResolver: MessageCodecResolver = EmptyMessageCodecResolver, + messageCodecResolver: MessageCodecResolver = EmptyMessageCodecResolver, ) : RpcClient { private val delegates = RpcInternalConcurrentHashMap() + private val messageCodecResolver = messageCodecResolver + ThrowingMessageCodecResolver public fun shutdown() { delegates.clear() @@ -93,7 +96,9 @@ public class GrpcClient internal constructor( } private inline fun withGrpcCall(call: RpcCall, body: (MethodDescriptor, Any) -> R): R { - require(call.arguments.size == 1) { "Call parameter size should be 1, but ${call.arguments.size}" } + require(call.arguments.size <= 1) { + "Call parameter size must be 0 or 1, but ${call.arguments.size}" + } val delegate = delegates.computeIfAbsent(call.descriptor.fqName) { val grpc = call.descriptor as? GrpcServiceDescriptor<*> @@ -107,8 +112,7 @@ public class GrpcClient internal constructor( as? MethodDescriptor ?: error("Expected a gRPC method descriptor") - val request = call.arguments[0] - ?: error("Expected a single argument for a gRPC call") + val request = call.arguments.getOrNull(0) ?: Unit return body(methodDescriptor, request) } diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt index 2ef8b1fbc..bfc19f700 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt @@ -18,6 +18,8 @@ import kotlinx.rpc.descriptor.unaryInvokator import kotlinx.rpc.grpc.annotations.Grpc import kotlinx.rpc.grpc.codec.EmptyMessageCodecResolver import kotlinx.rpc.grpc.codec.MessageCodecResolver +import kotlinx.rpc.grpc.codec.ThrowingMessageCodecResolver +import kotlinx.rpc.grpc.codec.plus import kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor import kotlinx.rpc.grpc.internal.MethodDescriptor import kotlinx.rpc.grpc.internal.MethodType @@ -46,13 +48,15 @@ private typealias ResponseServer = Any */ public class GrpcServer internal constructor( override val port: Int = 8080, - private val messageCodecResolver: MessageCodecResolver = EmptyMessageCodecResolver, + messageCodecResolver: MessageCodecResolver = EmptyMessageCodecResolver, parentContext: CoroutineContext = EmptyCoroutineContext, configure: ServerBuilder<*>.() -> Unit, ) : RpcServer, Server { private val internalContext = SupervisorJob(parentContext.job) private val internalScope = CoroutineScope(parentContext + internalContext) + private val messageCodecResolver = messageCodecResolver + ThrowingMessageCodecResolver + private var isBuilt = false private lateinit var internalServer: Server @@ -112,26 +116,26 @@ public class GrpcServer internal constructor( ): ServerMethodDefinition { return when (descriptor.type) { MethodType.UNARY -> { - internalScope.unaryServerMethodDefinition(descriptor) { request -> + internalScope.unaryServerMethodDefinition(descriptor, returnType.kType) { request -> unaryInvokator.call(service, arrayOf(request)) as ResponseServer } } MethodType.CLIENT_STREAMING -> { - internalScope.clientStreamingServerMethodDefinition(descriptor) { requests -> + internalScope.clientStreamingServerMethodDefinition(descriptor, returnType.kType) { requests -> unaryInvokator.call(service, arrayOf(requests)) as ResponseServer } } MethodType.SERVER_STREAMING -> { - internalScope.serverStreamingServerMethodDefinition(descriptor) { request -> + internalScope.serverStreamingServerMethodDefinition(descriptor, returnType.kType) { request -> @Suppress("UNCHECKED_CAST") flowInvokator.call(service, arrayOf(request)) as Flow } } MethodType.BIDI_STREAMING -> { - internalScope.bidiStreamingServerMethodDefinition(descriptor) { requests -> + internalScope.bidiStreamingServerMethodDefinition(descriptor, returnType.kType) { requests -> @Suppress("UNCHECKED_CAST") flowInvokator.call(service, arrayOf(requests)) as Flow } diff --git a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/suspendServerCalls.kt b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/suspendServerCalls.kt index 2f2af9ddd..2c16c6193 100644 --- a/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/suspendServerCalls.kt +++ b/grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/suspendServerCalls.kt @@ -22,10 +22,13 @@ import kotlinx.rpc.grpc.StatusCode import kotlinx.rpc.grpc.StatusException import kotlinx.rpc.grpc.StatusRuntimeException import kotlinx.rpc.internal.utils.InternalRpcApi +import kotlin.reflect.KType +import kotlin.reflect.typeOf @InternalRpcApi public fun CoroutineScope.unaryServerMethodDefinition( descriptor: MethodDescriptor, + responseKType: KType, implementation: suspend (request: Request) -> Response, ): ServerMethodDefinition { val type = descriptor.type @@ -33,7 +36,7 @@ public fun CoroutineScope.unaryServerMethodDefinition( "Expected a unary method descriptor but got $descriptor" } - return serverMethodDefinition(descriptor) { requests -> + return serverMethodDefinition(descriptor, responseKType) { requests -> requests .singleOrStatusFlow("request", descriptor) .map { implementation(it) } @@ -43,6 +46,7 @@ public fun CoroutineScope.unaryServerMethodDefinition( @InternalRpcApi public fun CoroutineScope.clientStreamingServerMethodDefinition( descriptor: MethodDescriptor, + responseKType: KType, implementation: suspend (requests: Flow) -> Response, ): ServerMethodDefinition { val type = descriptor.type @@ -50,7 +54,7 @@ public fun CoroutineScope.clientStreamingServerMethodDefinit "Expected a client streaming method descriptor but got $descriptor" } - return serverMethodDefinition(descriptor) { requests -> + return serverMethodDefinition(descriptor, responseKType) { requests -> flow { val response = implementation(requests) emit(response) @@ -61,6 +65,7 @@ public fun CoroutineScope.clientStreamingServerMethodDefinit @InternalRpcApi public fun CoroutineScope.serverStreamingServerMethodDefinition( descriptor: MethodDescriptor, + responseKType: KType, implementation: (request: Request) -> Flow, ): ServerMethodDefinition { val type = descriptor.type @@ -68,7 +73,7 @@ public fun CoroutineScope.serverStreamingServerMethodDefinit "Expected a server streaming method descriptor but got $descriptor" } - return serverMethodDefinition(descriptor) { requests -> + return serverMethodDefinition(descriptor, responseKType) { requests -> flow { requests .singleOrStatusFlow("request", descriptor) @@ -84,6 +89,7 @@ public fun CoroutineScope.serverStreamingServerMethodDefinit @InternalRpcApi public fun CoroutineScope.bidiStreamingServerMethodDefinition( descriptor: MethodDescriptor, + responseKType: KType, implementation: (requests: Flow) -> Flow, ): ServerMethodDefinition { val type = descriptor.type @@ -91,23 +97,26 @@ public fun CoroutineScope.bidiStreamingServerMethodDefinitio "Expected a bidi streaming method descriptor but got $descriptor" } - return serverMethodDefinition(descriptor, implementation) + return serverMethodDefinition(descriptor, responseKType, implementation) } private fun CoroutineScope.serverMethodDefinition( descriptor: MethodDescriptor, + responseKType: KType, implementation: (Flow) -> Flow, -): ServerMethodDefinition = serverMethodDefinition(descriptor, serverCallHandler(implementation)) +): ServerMethodDefinition = serverMethodDefinition(descriptor, serverCallHandler(responseKType, implementation)) private fun CoroutineScope.serverCallHandler( + responseKType: KType, implementation: (Flow) -> Flow, ): ServerCallHandler = ServerCallHandler { call, _ -> - serverCallListenerImpl(call, implementation) + serverCallListenerImpl(call, responseKType, implementation) } private fun CoroutineScope.serverCallListenerImpl( handler: ServerCall, + responseKType: KType, implementation: (Flow) -> Flow, ): ServerCall.Listener { val ready = Ready { handler.isReady()} @@ -139,7 +148,11 @@ private fun CoroutineScope.serverCallListenerImpl( val mutex = Mutex() val headersSent = AtomicBoolean(false) // enforces only sending headers once val failure = runCatching { - implementation(requests).collect { + implementation(requests).collect { response -> + @Suppress("UNCHECKED_CAST") + // fix for KRPC-173 + val value = if (responseKType == unitKType) Unit as Response else response + // once we have a response message, check if we've sent headers yet - if not, do so if (headersSent.value.compareAndSet(expect = false, update = true)) { mutex.withLock { @@ -148,7 +161,7 @@ private fun CoroutineScope.serverCallListenerImpl( } ready.suspendUntilReady() mutex.withLock { - handler.sendMessage(it) + handler.sendMessage(value) } } }.exceptionOrNull() @@ -228,3 +241,5 @@ private class AtomicBoolean(initialValue: Boolean) { private class ServerCallListenerState { var isReceiving = true } + +private val unitKType = typeOf() diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/RawClientServerTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/RawClientServerTest.kt index 5d756f0e7..98840b0a3 100644 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/RawClientServerTest.kt +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/RawClientServerTest.kt @@ -29,6 +29,7 @@ import kotlinx.rpc.grpc.internal.serverStreamingServerMethodDefinition import kotlinx.rpc.grpc.internal.serviceDescriptor import kotlinx.rpc.grpc.internal.unaryRpc import kotlinx.rpc.grpc.internal.unaryServerMethodDefinition +import kotlin.reflect.typeOf import kotlin.test.Test import kotlin.test.assertEquals @@ -40,7 +41,7 @@ class RawClientServerTest { methodName = "unary", type = MethodType.UNARY, methodDefinition = { descriptor -> - unaryServerMethodDefinition(descriptor) { it + it } + unaryServerMethodDefinition(descriptor, typeOf()) { it + it } }, ) { channel, descriptor -> val response = unaryRpc(channel, descriptor, "Hello") @@ -53,7 +54,7 @@ class RawClientServerTest { methodName = "serverStreaming", type = MethodType.SERVER_STREAMING, methodDefinition = { descriptor -> - serverStreamingServerMethodDefinition(descriptor) { + serverStreamingServerMethodDefinition(descriptor, typeOf()) { flowOf(it, it) } } @@ -68,7 +69,7 @@ class RawClientServerTest { methodName = "clientStreaming", type = MethodType.CLIENT_STREAMING, methodDefinition = { descriptor -> - clientStreamingServerMethodDefinition(descriptor) { + clientStreamingServerMethodDefinition(descriptor, typeOf()) { it.toList().joinToString(separator = "") } } @@ -83,7 +84,7 @@ class RawClientServerTest { methodName = "bidirectionalStreaming", type = MethodType.BIDI_STREAMING, methodDefinition = { descriptor -> - bidiStreamingServerMethodDefinition(descriptor) { + bidiStreamingServerMethodDefinition(descriptor, typeOf()) { it.map { str -> str + str } } } diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/BaseGrpcServiceTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/BaseGrpcServiceTest.kt new file mode 100644 index 000000000..04e08f276 --- /dev/null +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/BaseGrpcServiceTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.grpc.service + +import kotlinx.coroutines.delay +import kotlinx.coroutines.test.runTest +import kotlinx.rpc.grpc.GrpcClient +import kotlinx.rpc.grpc.GrpcServer +import kotlinx.rpc.grpc.annotations.Grpc +import kotlinx.rpc.grpc.codec.MessageCodecResolver +import kotlinx.rpc.withService +import kotlin.reflect.KClass + +abstract class BaseGrpcServiceTest { + protected inline fun <@Grpc reified Service : Any> runServiceTest( + resolver: MessageCodecResolver, + impl: Service, + noinline block: suspend (Service) -> Unit, + ) { + runServiceTest(Service::class, resolver, impl, block) + } + + protected fun <@Grpc Service : Any> runServiceTest( + kClass: KClass, + resolver: MessageCodecResolver, + impl: Service, + block: suspend (Service) -> Unit, + ) = runTest { + val server = GrpcServer( + port = PORT, + messageCodecResolver = resolver, + parentContext = coroutineContext, + builder = { + registerService(kClass) { impl } + } + ) + + server.start() + + val client = GrpcClient("localhost", PORT, messageCodecResolver = resolver) { + usePlaintext() + } + + val service = client.withService(kClass) + + block(service) + + client.shutdown() + client.awaitTermination() + server.shutdown() + server.awaitTermination() + } + + companion object { + const val PORT = 8082 + } +} + +suspend fun doWork(): String { + delay(1) + return "qwerty" +} diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/CustomResolverGrpcServiceTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/CustomResolverGrpcServiceTest.kt new file mode 100644 index 000000000..e68c002aa --- /dev/null +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/CustomResolverGrpcServiceTest.kt @@ -0,0 +1,158 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.grpc.service + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList +import kotlinx.io.Buffer +import kotlinx.io.Source +import kotlinx.io.readString +import kotlinx.io.writeString +import kotlinx.rpc.grpc.annotations.Grpc +import kotlinx.rpc.grpc.codec.MessageCodec +import kotlinx.rpc.grpc.codec.MessageCodecResolver +import kotlinx.rpc.grpc.codec.WithCodec +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals + +@WithCodec(Message.Companion::class) +class Message(val value: String) { + companion object : MessageCodec { + override fun encode(value: Message): Source { + return Buffer().apply { writeString(value.value) } + } + + override fun decode(stream: Source): Message { + return Message(stream.readString()) + } + } +} + +@Grpc +interface GrpcService { + suspend fun plainString(value: String): String + + suspend fun message(value: Message): Message + + suspend fun krpc173() + + suspend fun clientStreaming(flow: Flow): String + + fun serverStreaming(value: String): Flow + + fun bidiStreaming(flow: Flow): Flow +} + +class GrpcServiceImpl : GrpcService { + override suspend fun plainString(value: String): String { + return "$value $value" + } + + override suspend fun message(value: Message): Message { + return Message("${value.value} ${value.value}") + } + + override suspend fun krpc173() { + doWork() + } + + override suspend fun clientStreaming(flow: Flow): String { + return flow.toList().joinToString(" ") + } + + override fun serverStreaming(value: String): Flow { + return flowOf(value, value) + } + + override fun bidiStreaming(flow: Flow): Flow { + return flow.map { "$it $it" } + } +} + +class CustomResolverGrpcServiceTest : BaseGrpcServiceTest() { + @Test + fun testCodecResolver() = runServiceTest( + resolver = simpleResolver, + impl = GrpcServiceImpl(), + ) { service -> + assertEquals("test test", service.plainString("test")) + } + + @Test + fun testAnnotationCodec() = runServiceTest( + resolver = simpleResolver, + impl = GrpcServiceImpl(), + ) { service -> + assertEquals("test test", service.message(Message("test")).value) + } + + @Test + fun krpc173() = runServiceTest( + resolver = simpleResolver, + impl = GrpcServiceImpl(), + ) { service -> + assertEquals(Unit, service.krpc173()) + } + + @Test + fun clientStreaming() = runServiceTest( + resolver = simpleResolver, + impl = GrpcServiceImpl(), + ) { service -> + assertEquals("test test", service.clientStreaming(flowOf("test", "test"))) + } + + @Test + fun serverStreaming() = runServiceTest( + resolver = simpleResolver, + impl = GrpcServiceImpl(), + ) { service -> + assertEquals(listOf("test", "test"), service.serverStreaming("test").toList()) + } + + @Test + fun bidiStreaming() = runServiceTest( + resolver = simpleResolver, + impl = GrpcServiceImpl(), + ) { service -> + assertContentEquals( + expected = listOf("test test", "test test"), + actual = service.bidiStreaming(flowOf("test", "test")).toList(), + ) + } + + companion object { + private val simpleResolver = MessageCodecResolver { kType -> + when (kType.classifier) { + Unit::class -> unitCodec + String::class -> stringCodec + else -> null + } + } + + val stringCodec = object : MessageCodec { + override fun encode(value: String): Source { + return Buffer().apply { writeString(value) } + } + + override fun decode(stream: Source): String { + return stream.readString() + } + } + + val unitCodec = object : MessageCodec { + override fun encode(value: Unit): Source { + return Buffer() + } + + override fun decode(stream: Source) { + check(stream.exhausted()) + } + } + } +} diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/GrpcService.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/GrpcService.kt deleted file mode 100644 index 2aa54a022..000000000 --- a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/GrpcService.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.rpc.grpc.service - -import kotlinx.coroutines.test.runTest -import kotlinx.io.Buffer -import kotlinx.io.Source -import kotlinx.io.readString -import kotlinx.io.writeString -import kotlinx.rpc.grpc.GrpcClient -import kotlinx.rpc.grpc.GrpcServer -import kotlinx.rpc.grpc.annotations.Grpc -import kotlinx.rpc.grpc.codec.MessageCodec -import kotlinx.rpc.grpc.codec.MessageCodecResolver -import kotlinx.rpc.grpc.codec.WithCodec -import kotlinx.rpc.grpc.codec.kotlinx.serialization.asCodecResolver -import kotlinx.rpc.registerService -import kotlinx.rpc.withService -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlin.test.Test -import kotlin.test.assertEquals - -@WithCodec(Message.Companion::class) -class Message(val value: String) { - companion object : MessageCodec { - override fun encode(value: Message): Source { - return Buffer().apply { writeString(value.value) } - } - override fun decode(stream: Source): Message { - return Message(stream.readString()) - } - } -} - -@Serializable -class SerializableMessage(val value: String) - -@Grpc -interface GrpcService { - suspend fun plainString(value: String): String - - suspend fun message(value: Message): Message -} - -@Grpc -interface GrpcServiceSerializable { - suspend fun plainString(value: String): String - - suspend fun serialization(value: SerializableMessage): SerializableMessage -} - -class GrpcServiceImpl : GrpcService { - override suspend fun plainString(value: String): String { - return "$value $value" - } - - override suspend fun message(value: Message): Message { - return Message("${value.value} ${value.value}") - } -} - -class GrpcServiceSerializableImpl : GrpcServiceSerializable { - override suspend fun plainString(value: String): String { - return "$value $value" - } - - override suspend fun serialization(value: SerializableMessage): SerializableMessage { - return SerializableMessage("${value.value} ${value.value}") - } -} - -class GrpcGeneratedServiceTest { - @Test - fun testCodecResolver() = runServiceTest( - resolver = stringResolver, - impl = GrpcServiceImpl(), - ) { service -> - assertEquals("test test", service.plainString("test")) - } - - @Test - fun testAnnotationCodec() = runServiceTest( - resolver = stringResolver, - impl = GrpcServiceImpl(), - ) { service -> - assertEquals("test test", service.message(Message("test")).value) - } - - @Test - fun testSerializationCodec() = runServiceTest( - resolver = Json.asCodecResolver(), - impl = GrpcServiceSerializableImpl(), - ) { service -> - assertEquals("test test", service.plainString("test")) - - assertEquals("test test", service.serialization(SerializableMessage("test")).value) - } - - private inline fun <@Grpc reified Service : Any> runServiceTest( - resolver: MessageCodecResolver, - impl: Service, - crossinline block: suspend (Service) -> Unit, - ) = runTest { - val server = GrpcServer( - port = PORT, - messageCodecResolver = resolver, - parentContext = coroutineContext, - builder = { - registerService { impl } - } - ) - - server.start() - - val client = GrpcClient("localhost", PORT, messageCodecResolver = resolver) { - usePlaintext() - } - - val service = client.withService() - - block(service) - - client.shutdown() - client.awaitTermination() - server.shutdown() - server.awaitTermination() - } - - companion object { - private const val PORT = 8082 - - private val stringResolver = MessageCodecResolver { kType -> - check(kType.classifier == String::class) { "Unsupported type: $kType" } - simpleCodec - } - - val simpleCodec = object : MessageCodec { - override fun encode(value: String): Source { - return Buffer().apply { writeString(value) } - } - - override fun decode(stream: Source): String { - return stream.readString() - } - } - } -} diff --git a/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/SerializationGrpcServiceTest.kt b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/SerializationGrpcServiceTest.kt new file mode 100644 index 000000000..0ac1e2905 --- /dev/null +++ b/grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/service/SerializationGrpcServiceTest.kt @@ -0,0 +1,108 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.grpc.service + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList +import kotlinx.rpc.grpc.annotations.Grpc +import kotlinx.rpc.grpc.codec.kotlinx.serialization.asCodecResolver +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals + +@Serializable +class SerializableMessage(val value: String) + +@Grpc +interface GrpcServiceSerializable { + suspend fun plainString(value: String): String + + suspend fun serialization(value: SerializableMessage): SerializableMessage + + suspend fun krpc173() + + suspend fun clientStreaming(flow: Flow): String + + fun serverStreaming(value: String): Flow + + fun bidiStreaming(flow: Flow): Flow +} + +class GrpcServiceSerializableImpl : GrpcServiceSerializable { + override suspend fun plainString(value: String): String { + return "$value $value" + } + + override suspend fun serialization(value: SerializableMessage): SerializableMessage { + return SerializableMessage("${value.value} ${value.value}") + } + + override suspend fun krpc173() { + doWork() + } + + override suspend fun clientStreaming(flow: Flow): String { + return flow.toList().joinToString(" ") + } + + override fun serverStreaming(value: String): Flow { + return flowOf(value, value) + } + + override fun bidiStreaming(flow: Flow): Flow { + return flow.map { "$it $it" } + } +} + +class SerializationGrpcServiceTest : BaseGrpcServiceTest() { + @Test + fun testSerializationCodec() = runServiceTest( + resolver = Json.asCodecResolver(), + impl = GrpcServiceSerializableImpl(), + ) { service -> + assertEquals("test test", service.plainString("test")) + + assertEquals("test test", service.serialization(SerializableMessage("test")).value) + } + + @Test + fun krpc173() = runServiceTest( + resolver = Json.asCodecResolver(), + impl = GrpcServiceSerializableImpl(), + ) { service -> + assertEquals(Unit, service.krpc173()) + } + + @Test + fun clientStreaming() = runServiceTest( + resolver = Json.asCodecResolver(), + impl = GrpcServiceImpl(), + ) { service -> + assertEquals("test test", service.clientStreaming(flowOf("test", "test"))) + } + + @Test + fun serverStreaming() = runServiceTest( + resolver = Json.asCodecResolver(), + impl = GrpcServiceImpl(), + ) { service -> + assertEquals(listOf("test", "test"), service.serverStreaming("test").toList()) + } + + @Test + fun bidiStreaming() = runServiceTest( + resolver = Json.asCodecResolver(), + impl = GrpcServiceImpl(), + ) { service -> + assertContentEquals( + expected = listOf("test test", "test test"), + actual = service.bidiStreaming(flowOf("test", "test")).toList(), + ) + } +} diff --git a/krpc/krpc-server/src/commonMain/kotlin/kotlinx/rpc/krpc/server/internal/KrpcServerService.kt b/krpc/krpc-server/src/commonMain/kotlin/kotlinx/rpc/krpc/server/internal/KrpcServerService.kt index b3080864e..fb9ac7aae 100644 --- a/krpc/krpc-server/src/commonMain/kotlin/kotlinx/rpc/krpc/server/internal/KrpcServerService.kt +++ b/krpc/krpc-server/src/commonMain/kotlin/kotlinx/rpc/krpc/server/internal/KrpcServerService.kt @@ -155,7 +155,7 @@ internal class KrpcServerService<@Rpc T : Any>( is RpcInvokator.UnaryResponse -> { val value = invokator.call(service, data).let { interceptedValue -> // KRPC-173 - if (callable.returnType.kType == typeOf()) { + if (callable.returnType.kType == unitKType) { Unit } else { interceptedValue @@ -378,3 +378,5 @@ internal class RpcRequest(val handlerJob: Job, val streamContext: ServerStreamCo streamContext.removeCall(callId, cause) } } + +private val unitKType = typeOf() diff --git a/tests/compiler-plugin-tests/build.gradle.kts b/tests/compiler-plugin-tests/build.gradle.kts index e60bc07d6..ae6ff52d7 100644 --- a/tests/compiler-plugin-tests/build.gradle.kts +++ b/tests/compiler-plugin-tests/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { testPriorityRuntimeClasspath(libs.intellij.util) { isTransitive = false } implementation(projects.core) + implementation(projects.grpc.grpcCore) testRuntimeOnly(libs.kotlin.test) testRuntimeOnly(libs.kotlin.script.runtime) @@ -100,6 +101,9 @@ dependencies { testImplementation(libs.junit5.platform.suite.api) testDataClasspath(projects.utils) + testDataClasspath(projects.grpc.grpcCodec) + testDataClasspath(projects.grpc.grpcCore) + testDataClasspath(libs.kotlinx.io.core) testDataClasspath(libs.coroutines.core) } diff --git a/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/Grpc.kt b/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/Grpc.kt new file mode 100644 index 000000000..7d1adbf27 --- /dev/null +++ b/tests/compiler-plugin-tests/src/main/kotlin/kotlinx/rpc/codegen/test/Grpc.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.codegen.test + +import io.grpc.MethodDescriptor +import kotlinx.io.Source +import kotlinx.rpc.descriptor.serviceDescriptorOf +import kotlinx.rpc.grpc.annotations.Grpc +import kotlinx.rpc.grpc.codec.MessageCodec +import kotlinx.rpc.grpc.codec.MessageCodecResolver +import kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate +import kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor +import kotlin.reflect.KType + +/** + * To check in methods: + * ``` + * bareMethodName + * type + * serviceName + * isSafe + * isIdempotent + * isSampledToLocalTracing + * ``` + * + * Types: + * ``` + * MethodDescriptor.MethodType.UNARY + * MethodDescriptor.MethodType.SERVER_STREAMING + * MethodDescriptor.MethodType.CLIENT_STREAMING + * MethodDescriptor.MethodType.BIDI_STREAMING + * ``` + */ +@Suppress("unused") +inline fun <@Grpc reified T : Any> grpcDelegate(): GrpcServiceDelegate { + val descriptor = serviceDescriptorOf() as GrpcServiceDescriptor + val delegate = descriptor.delegate(SimpleResolver) + + return delegate +} + +fun MethodDescriptor<*, *>.checkMethod( + expectedMethodName: String, + expectedMethodType: MethodDescriptor.MethodType, + expectedServiceName: String, + expectedIsSafe: Boolean = true, + expectedIsIdempotent: Boolean = true, + expectedIsSampledToLocalTracing: Boolean = true, +): String? { + return when { + bareMethodName != expectedMethodName -> "wrong bareMethodName: $bareMethodName" + type != expectedMethodType -> "wrong type: $type" + serviceName != expectedServiceName -> "wrong service name: $fullMethodName" + isSafe != expectedIsSafe -> "wrong isSafe: $isSafe" + isIdempotent != expectedIsIdempotent -> "wrong isIdempotent: $isIdempotent" + isSampledToLocalTracing != expectedIsSampledToLocalTracing -> "wrong isSampledToLocalTracing: $isSampledToLocalTracing" + else -> null + } +} + +object SimpleResolver : MessageCodecResolver { + override fun resolveOrNull(kType: KType): MessageCodec<*>? { + return when (kType.classifier) { + String::class -> StringCodec + Unit::class -> UnitCodec + Message::class -> MessageClassCodec + else -> null + } + } +} + +object StringCodec : MessageCodec { + override fun encode(value: String): Source { + TODO("Not yet implemented") + } + + override fun decode(stream: Source): String { + TODO("Not yet implemented") + } +} + +object UnitCodec : MessageCodec { + override fun encode(value: String): Source { + TODO("Not yet implemented") + } + + override fun decode(stream: Source): String { + TODO("Not yet implemented") + } +} + +@Suppress("unused") +class Message(val a: Int, val b: String) + +object MessageClassCodec : MessageCodec { + override fun encode(value: Message): Source { + TODO("Not yet implemented") + } + + override fun decode(stream: Source): Message { + TODO("Not yet implemented") + } +} diff --git a/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/BoxTestGenerated.java b/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/BoxTestGenerated.java index b204c706c..e29c721ec 100644 --- a/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/BoxTestGenerated.java +++ b/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/BoxTestGenerated.java @@ -1,5 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + package kotlinx.rpc.codegen.test.runners; import com.intellij.testFramework.TestDataPath; @@ -33,6 +37,12 @@ public void testFlowParameter() { runTest("src/testData/box/flowParameter.kt"); } + @Test + @TestMetadata("grpc.kt") + public void testGrpc() { + runTest("src/testData/box/grpc.kt"); + } + @Test @TestMetadata("multiModule.kt") public void testMultiModule() { diff --git a/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/DiagnosticTestGenerated.java b/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/DiagnosticTestGenerated.java index 2362e290c..3bc448f56 100644 --- a/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/DiagnosticTestGenerated.java +++ b/tests/compiler-plugin-tests/src/test-gen/kotlinx/rpc/codegen/test/runners/DiagnosticTestGenerated.java @@ -1,5 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + package kotlinx.rpc.codegen.test.runners; import com.intellij.testFramework.TestDataPath; @@ -27,6 +31,12 @@ public void testCheckedAnnotation() { runTest("src/testData/diagnostics/checkedAnnotation.kt"); } + @Test + @TestMetadata("grpc.kt") + public void testGrpc() { + runTest("src/testData/diagnostics/grpc.kt"); + } + @Test @TestMetadata("rpcChecked.kt") public void testRpcChecked() { @@ -44,4 +54,10 @@ public void testRpcService() { public void testStrictMode() { runTest("src/testData/diagnostics/strictMode.kt"); } + + @Test + @TestMetadata("withCodec.kt") + public void testWithCodec() { + runTest("src/testData/diagnostics/withCodec.kt"); + } } diff --git a/tests/compiler-plugin-tests/src/testData/box/grpc.fir.ir.txt b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.ir.txt new file mode 100644 index 000000000..3054ad8c1 --- /dev/null +++ b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.ir.txt @@ -0,0 +1,964 @@ +FILE fqName: fileName:/grpc.kt + annotations: + OptIn(markerClass = [CLASS_REFERENCE 'CLASS IR_EXTERNAL_DECLARATION_STUB ANNOTATION_CLASS name:ExperimentalRpcApi modality:OPEN visibility:public superTypes:[kotlin.Annotation]' type=kotlin.reflect.KClass, CLASS_REFERENCE 'CLASS IR_EXTERNAL_DECLARATION_STUB ANNOTATION_CLASS name:InternalRpcApi modality:OPEN visibility:public superTypes:[kotlin.Annotation]' type=kotlin.reflect.KClass] type=kotlin.Array> varargElementType=kotlin.reflect.KClass) + CLASS CLASS name:Custom modality:FINAL visibility:public superTypes:[kotlin.Any] + annotations: + WithCodec(codec = CLASS_REFERENCE 'CLASS OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.grpc.codec.MessageCodec<.Custom>]' type=kotlin.reflect.KClass<.Custom.Companion>) + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.Custom + PROPERTY name:content visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:content type:kotlin.String visibility:private [final] + EXPRESSION_BODY + GET_VAR 'content: kotlin.String declared in .Custom.' type=kotlin.String origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL returnType:kotlin.String + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Custom + correspondingProperty: PROPERTY name:content visibility:public modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .Custom' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:content type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .Custom declared in .Custom.' type=.Custom origin=null + CLASS OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.grpc.codec.MessageCodec<.Custom>] + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.Custom.Companion + CONSTRUCTOR visibility:private returnType:.Custom.Companion [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.grpc.codec.MessageCodec<.Custom>]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlinx.rpc.grpc.codec.MessageCodec + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlinx.rpc.grpc.codec.MessageCodec + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlinx.rpc.grpc.codec.MessageCodec + FUN name:decode visibility:public modality:OPEN returnType:.Custom + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Custom.Companion + VALUE_PARAMETER kind:Regular name:stream index:1 type:kotlinx.io.Source + overridden: + public abstract fun decode (stream: kotlinx.io.Source): T of kotlinx.rpc.grpc.codec.MessageCodec declared in kotlinx.rpc.grpc.codec.MessageCodec + BLOCK_BODY + CALL 'public final fun TODO (reason: kotlin.String): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null + ARG reason: CONST String type=kotlin.String value="Not yet implemented" + FUN name:encode visibility:public modality:OPEN returnType:kotlinx.io.Source + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Custom.Companion + VALUE_PARAMETER kind:Regular name:value index:1 type:.Custom + overridden: + public abstract fun encode (value: T of kotlinx.rpc.grpc.codec.MessageCodec): kotlinx.io.Source declared in kotlinx.rpc.grpc.codec.MessageCodec + BLOCK_BODY + CALL 'public final fun TODO (reason: kotlin.String): kotlin.Nothing declared in kotlin' type=kotlin.Nothing origin=null + ARG reason: CONST String type=kotlin.String value="Not yet implemented" + CONSTRUCTOR visibility:public returnType:.Custom [primary] + VALUE_PARAMETER kind:Regular name:content index:0 type:kotlin.String + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Custom modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + CLASS INTERFACE name:BoxService modality:ABSTRACT visibility:public superTypes:[kotlin.Any] + annotations: + Grpc + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.BoxService + CLASS GENERATED[kotlinx.rpc.codegen.RpcGeneratedStubKey] CLASS name:$rpcServiceStub modality:FINAL visibility:public superTypes:[.BoxService] + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.BoxService.$rpcServiceStub + PROPERTY name:__rpc_stub_id visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:__rpc_stub_id type:kotlin.Long visibility:private [final] + EXPRESSION_BODY + GET_VAR '__rpc_stub_id: kotlin.Long declared in .BoxService.$rpcServiceStub.' type=kotlin.Long origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlin.Long + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + correspondingProperty: PROPERTY name:__rpc_stub_id visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlin.Long declared in .BoxService.$rpcServiceStub' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:__rpc_stub_id type:kotlin.Long visibility:private [final]' type=kotlin.Long origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.' type=.BoxService.$rpcServiceStub origin=null + PROPERTY name:__rpc_client visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:__rpc_client type:kotlinx.rpc.RpcClient visibility:private [final] + EXPRESSION_BODY + GET_VAR '__rpc_client: kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub.' type=kotlinx.rpc.RpcClient origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlinx.rpc.RpcClient + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + correspondingProperty: PROPERTY name:__rpc_client visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:__rpc_client type:kotlinx.rpc.RpcClient visibility:private [final]' type=kotlinx.rpc.RpcClient origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.' type=.BoxService.$rpcServiceStub origin=null + CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>] + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.BoxService.$rpcServiceStub.Companion + PROPERTY name:simpleName visibility:public modality:FINAL [val] + overridden: + public abstract simpleName: kotlin.String declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + FIELD PROPERTY_BACKING_FIELD name:simpleName type:kotlin.String visibility:private [final] + EXPRESSION_BODY + CONST String type=kotlin.String value="BoxService" + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL returnType:kotlin.String + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:simpleName visibility:public modality:FINAL [val] + overridden: + public abstract fun (): kotlin.String declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:simpleName type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:fqName visibility:public modality:FINAL [val] + overridden: + public abstract fqName: kotlin.String declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + FIELD PROPERTY_BACKING_FIELD name:fqName type:kotlin.String visibility:private [final] + EXPRESSION_BODY + CONST String type=kotlin.String value="BoxService" + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL returnType:kotlin.String + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:fqName visibility:public modality:FINAL [val] + overridden: + public abstract fun (): kotlin.String declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.String declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:fqName type:kotlin.String visibility:private [final]' type=kotlin.String origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:simpleInvokator visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:simpleInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final] + EXPRESSION_BODY + TYPE_OP type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=SAM_CONVERSION typeOperand=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + FUN_EXPR type=kotlin.coroutines.SuspendFunction2<.BoxService, kotlin.Array, kotlin.Any?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Any? [suspend] + VALUE_PARAMETER kind:Regular name:service index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:arguments index:1 type:kotlin.Array + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (service: .BoxService, arguments: kotlin.Array): kotlin.Any? declared in .BoxService.$rpcServiceStub.Companion.simpleInvokator' + CALL 'public abstract fun simple (value: kotlin.String): kotlin.String declared in .BoxService' type=kotlin.String origin=null + ARG : GET_VAR 'service: .BoxService declared in .BoxService.$rpcServiceStub.Companion.simpleInvokator.' type=.BoxService origin=null + ARG value: TYPE_OP type=kotlin.String origin=CAST typeOperand=kotlin.String + CALL 'public final fun get (index: kotlin.Int): T of kotlin.Array declared in kotlin.Array' type=kotlin.Any? origin=GET_ARRAY_ELEMENT + ARG : GET_VAR 'arguments: kotlin.Array declared in .BoxService.$rpcServiceStub.Companion.simpleInvokator.' type=kotlin.Array origin=null + ARG index: CONST Int type=kotlin.Int value=0 + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:simpleInvokator visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:simpleInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final]' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:unitInvokator visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:unitInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final] + EXPRESSION_BODY + TYPE_OP type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=SAM_CONVERSION typeOperand=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + FUN_EXPR type=kotlin.coroutines.SuspendFunction2<.BoxService, kotlin.Array, kotlin.Any?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Any? [suspend] + VALUE_PARAMETER kind:Regular name:service index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:arguments index:1 type:kotlin.Array + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (service: .BoxService, arguments: kotlin.Array): kotlin.Any? declared in .BoxService.$rpcServiceStub.Companion.unitInvokator' + CALL 'public abstract fun unit (): kotlin.Unit declared in .BoxService' type=kotlin.Unit origin=null + ARG : GET_VAR 'service: .BoxService declared in .BoxService.$rpcServiceStub.Companion.unitInvokator.' type=.BoxService origin=null + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:unitInvokator visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:unitInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final]' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:clientStreamInvokator visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:clientStreamInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final] + EXPRESSION_BODY + TYPE_OP type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=SAM_CONVERSION typeOperand=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + FUN_EXPR type=kotlin.coroutines.SuspendFunction2<.BoxService, kotlin.Array, kotlin.Any?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Any? [suspend] + VALUE_PARAMETER kind:Regular name:service index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:arguments index:1 type:kotlin.Array + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (service: .BoxService, arguments: kotlin.Array): kotlin.Any? declared in .BoxService.$rpcServiceStub.Companion.clientStreamInvokator' + CALL 'public abstract fun clientStream (flow: kotlinx.coroutines.flow.Flow): kotlin.Unit declared in .BoxService' type=kotlin.Unit origin=null + ARG : GET_VAR 'service: .BoxService declared in .BoxService.$rpcServiceStub.Companion.clientStreamInvokator.' type=.BoxService origin=null + ARG flow: TYPE_OP type=kotlinx.coroutines.flow.Flow origin=CAST typeOperand=kotlinx.coroutines.flow.Flow + CALL 'public final fun get (index: kotlin.Int): T of kotlin.Array declared in kotlin.Array' type=kotlin.Any? origin=GET_ARRAY_ELEMENT + ARG : GET_VAR 'arguments: kotlin.Array declared in .BoxService.$rpcServiceStub.Companion.clientStreamInvokator.' type=kotlin.Array origin=null + ARG index: CONST Int type=kotlin.Int value=0 + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:clientStreamInvokator visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:clientStreamInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final]' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:serverStreamInvokator visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:serverStreamInvokator type:kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> visibility:private [final] + EXPRESSION_BODY + TYPE_OP type=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> origin=SAM_CONVERSION typeOperand=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> + FUN_EXPR type=kotlin.Function2<.BoxService, kotlin.Array, kotlinx.coroutines.flow.Flow> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlinx.coroutines.flow.Flow + VALUE_PARAMETER kind:Regular name:service index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:arguments index:1 type:kotlin.Array + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (service: .BoxService, arguments: kotlin.Array): kotlinx.coroutines.flow.Flow declared in .BoxService.$rpcServiceStub.Companion.serverStreamInvokator' + CALL 'public abstract fun serverStream (): kotlinx.coroutines.flow.Flow declared in .BoxService' type=kotlinx.coroutines.flow.Flow origin=null + ARG : GET_VAR 'service: .BoxService declared in .BoxService.$rpcServiceStub.Companion.serverStreamInvokator.' type=.BoxService origin=null + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:serverStreamInvokator visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:serverStreamInvokator type:kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> visibility:private [final]' type=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:bidiStreamInvokator visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:bidiStreamInvokator type:kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> visibility:private [final] + EXPRESSION_BODY + TYPE_OP type=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> origin=SAM_CONVERSION typeOperand=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> + FUN_EXPR type=kotlin.Function2<.BoxService, kotlin.Array, kotlinx.coroutines.flow.Flow> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlinx.coroutines.flow.Flow + VALUE_PARAMETER kind:Regular name:service index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:arguments index:1 type:kotlin.Array + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (service: .BoxService, arguments: kotlin.Array): kotlinx.coroutines.flow.Flow declared in .BoxService.$rpcServiceStub.Companion.bidiStreamInvokator' + CALL 'public abstract fun bidiStream (flow: kotlinx.coroutines.flow.Flow): kotlinx.coroutines.flow.Flow declared in .BoxService' type=kotlinx.coroutines.flow.Flow origin=null + ARG : GET_VAR 'service: .BoxService declared in .BoxService.$rpcServiceStub.Companion.bidiStreamInvokator.' type=.BoxService origin=null + ARG flow: TYPE_OP type=kotlinx.coroutines.flow.Flow origin=CAST typeOperand=kotlinx.coroutines.flow.Flow + CALL 'public final fun get (index: kotlin.Int): T of kotlin.Array declared in kotlin.Array' type=kotlin.Any? origin=GET_ARRAY_ELEMENT + ARG : GET_VAR 'arguments: kotlin.Array declared in .BoxService.$rpcServiceStub.Companion.bidiStreamInvokator.' type=kotlin.Array origin=null + ARG index: CONST Int type=kotlin.Int value=0 + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:bidiStreamInvokator visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:bidiStreamInvokator type:kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> visibility:private [final]' type=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:customInvokator visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:customInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final] + EXPRESSION_BODY + TYPE_OP type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=SAM_CONVERSION typeOperand=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + FUN_EXPR type=kotlin.coroutines.SuspendFunction2<.BoxService, kotlin.Array, kotlin.Any?> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Any? [suspend] + VALUE_PARAMETER kind:Regular name:service index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:arguments index:1 type:kotlin.Array + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (service: .BoxService, arguments: kotlin.Array): kotlin.Any? declared in .BoxService.$rpcServiceStub.Companion.customInvokator' + CALL 'public abstract fun custom (): .Custom declared in .BoxService' type=.Custom origin=null + ARG : GET_VAR 'service: .BoxService declared in .BoxService.$rpcServiceStub.Companion.customInvokator.' type=.BoxService origin=null + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:customInvokator visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:customInvokator type:kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> visibility:private [final]' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + PROPERTY name:callableMap visibility:private modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:callableMap type:kotlin.collections.Map.BoxService>> visibility:private [final] + EXPRESSION_BODY + CALL 'public final fun mapOf (vararg pairs: kotlin.Pair): kotlin.collections.Map declared in kotlin.collections' type=kotlin.collections.Map.BoxService>> origin=null + TYPE_ARG K: kotlin.String + TYPE_ARG V: kotlinx.rpc.descriptor.RpcCallable<.BoxService> + ARG pairs: VARARG type=kotlin.Array.BoxService>>> varargElementType=kotlin.Pair.BoxService>> + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair.BoxService>> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: kotlinx.rpc.descriptor.RpcCallable<.BoxService> + ARG : CONST String type=kotlin.String value="simple" + ARG that: CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, returnType: kotlinx.rpc.descriptor.RpcType, invokator: kotlinx.rpc.descriptor.RpcInvokator, parameters: kotlin.Array) declared in kotlinx.rpc.descriptor.RpcCallableDefault' type=kotlinx.rpc.descriptor.RpcCallable<.BoxService> origin=null + TYPE_ARG Service: .BoxService + ARG name: CONST String type=kotlin.String value="simple" + ARG returnType: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.String + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG invokator: CALL 'private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion' type=.BoxService.$rpcServiceStub.Companion origin=null + ARG parameters: CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlinx.rpc.descriptor.RpcParameter + ARG elements: VARARG type=kotlin.Array varargElementType=kotlinx.rpc.descriptor.RpcParameter + CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, type: kotlinx.rpc.descriptor.RpcType, isOptional: kotlin.Boolean, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcParameterDefault' type=kotlinx.rpc.descriptor.RpcParameter origin=null + ARG name: CONST String type=kotlin.String value="value" + ARG type: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.String + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG isOptional: CONST Boolean type=kotlin.Boolean value=false + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair.BoxService>> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: kotlinx.rpc.descriptor.RpcCallable<.BoxService> + ARG : CONST String type=kotlin.String value="unit" + ARG that: CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, returnType: kotlinx.rpc.descriptor.RpcType, invokator: kotlinx.rpc.descriptor.RpcInvokator, parameters: kotlin.Array) declared in kotlinx.rpc.descriptor.RpcCallableDefault' type=kotlinx.rpc.descriptor.RpcCallable<.BoxService> origin=null + TYPE_ARG Service: .BoxService + ARG name: CONST String type=kotlin.String value="unit" + ARG returnType: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG invokator: CALL 'private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion' type=.BoxService.$rpcServiceStub.Companion origin=null + ARG parameters: CALL 'public final fun emptyArray (): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlinx.rpc.descriptor.RpcParameter + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair.BoxService>> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: kotlinx.rpc.descriptor.RpcCallable<.BoxService> + ARG : CONST String type=kotlin.String value="clientStream" + ARG that: CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, returnType: kotlinx.rpc.descriptor.RpcType, invokator: kotlinx.rpc.descriptor.RpcInvokator, parameters: kotlin.Array) declared in kotlinx.rpc.descriptor.RpcCallableDefault' type=kotlinx.rpc.descriptor.RpcCallable<.BoxService> origin=null + TYPE_ARG Service: .BoxService + ARG name: CONST String type=kotlin.String value="clientStream" + ARG returnType: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG invokator: CALL 'private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion' type=.BoxService.$rpcServiceStub.Companion origin=null + ARG parameters: CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlinx.rpc.descriptor.RpcParameter + ARG elements: VARARG type=kotlin.Array varargElementType=kotlinx.rpc.descriptor.RpcParameter + CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, type: kotlinx.rpc.descriptor.RpcType, isOptional: kotlin.Boolean, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcParameterDefault' type=kotlinx.rpc.descriptor.RpcParameter origin=null + ARG name: CONST String type=kotlin.String value="flow" + ARG type: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlinx.coroutines.flow.Flow + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG isOptional: CONST Boolean type=kotlin.Boolean value=false + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair.BoxService>> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: kotlinx.rpc.descriptor.RpcCallable<.BoxService> + ARG : CONST String type=kotlin.String value="serverStream" + ARG that: CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, returnType: kotlinx.rpc.descriptor.RpcType, invokator: kotlinx.rpc.descriptor.RpcInvokator, parameters: kotlin.Array) declared in kotlinx.rpc.descriptor.RpcCallableDefault' type=kotlinx.rpc.descriptor.RpcCallable<.BoxService> origin=null + TYPE_ARG Service: .BoxService + ARG name: CONST String type=kotlin.String value="serverStream" + ARG returnType: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG invokator: CALL 'private final fun (): kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' type=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion' type=.BoxService.$rpcServiceStub.Companion origin=null + ARG parameters: CALL 'public final fun emptyArray (): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlinx.rpc.descriptor.RpcParameter + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair.BoxService>> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: kotlinx.rpc.descriptor.RpcCallable<.BoxService> + ARG : CONST String type=kotlin.String value="bidiStream" + ARG that: CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, returnType: kotlinx.rpc.descriptor.RpcType, invokator: kotlinx.rpc.descriptor.RpcInvokator, parameters: kotlin.Array) declared in kotlinx.rpc.descriptor.RpcCallableDefault' type=kotlinx.rpc.descriptor.RpcCallable<.BoxService> origin=null + TYPE_ARG Service: .BoxService + ARG name: CONST String type=kotlin.String value="bidiStream" + ARG returnType: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlinx.rpc.codegen.test.Message + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG invokator: CALL 'private final fun (): kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' type=kotlinx.rpc.descriptor.RpcInvokator.FlowResponse<.BoxService> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion' type=.BoxService.$rpcServiceStub.Companion origin=null + ARG parameters: CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlinx.rpc.descriptor.RpcParameter + ARG elements: VARARG type=kotlin.Array varargElementType=kotlinx.rpc.descriptor.RpcParameter + CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, type: kotlinx.rpc.descriptor.RpcType, isOptional: kotlin.Boolean, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcParameterDefault' type=kotlinx.rpc.descriptor.RpcParameter origin=null + ARG name: CONST String type=kotlin.String value="flow" + ARG type: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlinx.coroutines.flow.Flow + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG isOptional: CONST Boolean type=kotlin.Boolean value=false + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair.BoxService>> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: kotlinx.rpc.descriptor.RpcCallable<.BoxService> + ARG : CONST String type=kotlin.String value="custom" + ARG that: CONSTRUCTOR_CALL 'public constructor (name: kotlin.String, returnType: kotlinx.rpc.descriptor.RpcType, invokator: kotlinx.rpc.descriptor.RpcInvokator, parameters: kotlin.Array) declared in kotlinx.rpc.descriptor.RpcCallableDefault' type=kotlinx.rpc.descriptor.RpcCallable<.BoxService> origin=null + TYPE_ARG Service: .BoxService + ARG name: CONST String type=kotlin.String value="custom" + ARG returnType: CONSTRUCTOR_CALL 'public constructor (kType: kotlin.reflect.KType, annotations: kotlin.collections.List) declared in kotlinx.rpc.descriptor.RpcTypeDefault' type=kotlinx.rpc.descriptor.RpcType origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: .Custom + ARG annotations: CALL 'public final fun emptyList (): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.Annotation + ARG invokator: CALL 'private final fun (): kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> declared in .BoxService.$rpcServiceStub.Companion' type=kotlinx.rpc.descriptor.RpcInvokator.UnaryResponse<.BoxService> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion' type=.BoxService.$rpcServiceStub.Companion origin=null + ARG parameters: CALL 'public final fun emptyArray (): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlinx.rpc.descriptor.RpcParameter + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:private modality:FINAL returnType:kotlin.collections.Map.BoxService>> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:callableMap visibility:private modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='private final fun (): kotlin.collections.Map.BoxService>> declared in .BoxService.$rpcServiceStub.Companion' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:callableMap type:kotlin.collections.Map.BoxService>> visibility:private [final]' type=kotlin.collections.Map.BoxService>> origin=null + receiver: GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + CONSTRUCTOR visibility:private returnType:.BoxService.$rpcServiceStub.Companion [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + FUN name:createInstance visibility:public modality:OPEN returnType:.BoxService + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + VALUE_PARAMETER kind:Regular name:serviceId index:1 type:kotlin.Long + VALUE_PARAMETER kind:Regular name:client index:2 type:kotlinx.rpc.RpcClient + overridden: + public abstract fun createInstance (serviceId: kotlin.Long, client: kotlinx.rpc.RpcClient): Service of kotlinx.rpc.descriptor.RpcServiceDescriptor declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun createInstance (serviceId: kotlin.Long, client: kotlinx.rpc.RpcClient): .BoxService declared in .BoxService.$rpcServiceStub.Companion' + CONSTRUCTOR_CALL 'public constructor (__rpc_stub_id: kotlin.Long, __rpc_client: kotlinx.rpc.RpcClient) declared in .BoxService.$rpcServiceStub' type=.BoxService.$rpcServiceStub origin=null + ARG __rpc_stub_id: GET_VAR 'serviceId: kotlin.Long declared in .BoxService.$rpcServiceStub.Companion.createInstance' type=kotlin.Long origin=null + ARG __rpc_client: GET_VAR 'client: kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub.Companion.createInstance' type=kotlinx.rpc.RpcClient origin=null + FUN name:delegate visibility:public modality:FINAL returnType:kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + VALUE_PARAMETER kind:Regular name:resolver index:1 type:kotlinx.rpc.grpc.codec.MessageCodecResolver + overridden: + public abstract fun delegate (resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver): kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor + BLOCK_BODY + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.collections.Map> [val] + CALL 'public final fun mapOf (vararg pairs: kotlin.Pair): kotlin.collections.Map declared in kotlin.collections' type=kotlin.collections.Map> origin=null + TYPE_ARG K: kotlin.String + TYPE_ARG V: io.grpc.MethodDescriptor<*, *> + ARG pairs: VARARG type=kotlin.Array>> varargElementType=kotlin.Pair> + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: io.grpc.MethodDescriptor<*, *> + ARG : CONST String type=kotlin.String value="simple" + ARG that: CALL 'public final fun methodDescriptor (fullMethodName: kotlin.String, requestCodec: kotlinx.rpc.grpc.codec.MessageCodec, responseCodec: kotlinx.rpc.grpc.codec.MessageCodec, type: kotlinx.rpc.grpc.internal.MethodType, schemaDescriptor: kotlin.Any?, idempotent: kotlin.Boolean, safe: kotlin.Boolean, sampledToLocalTracing: kotlin.Boolean): io.grpc.MethodDescriptor declared in kotlinx.rpc.grpc.internal' type=io.grpc.MethodDescriptor origin=null + TYPE_ARG Request: kotlin.String + TYPE_ARG Response: kotlin.String + ARG fullMethodName: CONST String type=kotlin.String value="BoxService/simple" + ARG requestCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.String + ARG responseCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.String + ARG type: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:UNARY' type=kotlinx.rpc.grpc.internal.MethodType + ARG schemaDescriptor: CONST Null type=kotlin.Any? value=null + ARG idempotent: CONST Boolean type=kotlin.Boolean value=true + ARG safe: CONST Boolean type=kotlin.Boolean value=true + ARG sampledToLocalTracing: CONST Boolean type=kotlin.Boolean value=true + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: io.grpc.MethodDescriptor<*, *> + ARG : CONST String type=kotlin.String value="unit" + ARG that: CALL 'public final fun methodDescriptor (fullMethodName: kotlin.String, requestCodec: kotlinx.rpc.grpc.codec.MessageCodec, responseCodec: kotlinx.rpc.grpc.codec.MessageCodec, type: kotlinx.rpc.grpc.internal.MethodType, schemaDescriptor: kotlin.Any?, idempotent: kotlin.Boolean, safe: kotlin.Boolean, sampledToLocalTracing: kotlin.Boolean): io.grpc.MethodDescriptor declared in kotlinx.rpc.grpc.internal' type=io.grpc.MethodDescriptor origin=null + TYPE_ARG Request: kotlin.Unit + TYPE_ARG Response: kotlin.Unit + ARG fullMethodName: CONST String type=kotlin.String value="BoxService/unit" + ARG requestCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG responseCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG type: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:UNARY' type=kotlinx.rpc.grpc.internal.MethodType + ARG schemaDescriptor: CONST Null type=kotlin.Any? value=null + ARG idempotent: CONST Boolean type=kotlin.Boolean value=true + ARG safe: CONST Boolean type=kotlin.Boolean value=true + ARG sampledToLocalTracing: CONST Boolean type=kotlin.Boolean value=true + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: io.grpc.MethodDescriptor<*, *> + ARG : CONST String type=kotlin.String value="clientStream" + ARG that: CALL 'public final fun methodDescriptor (fullMethodName: kotlin.String, requestCodec: kotlinx.rpc.grpc.codec.MessageCodec, responseCodec: kotlinx.rpc.grpc.codec.MessageCodec, type: kotlinx.rpc.grpc.internal.MethodType, schemaDescriptor: kotlin.Any?, idempotent: kotlin.Boolean, safe: kotlin.Boolean, sampledToLocalTracing: kotlin.Boolean): io.grpc.MethodDescriptor declared in kotlinx.rpc.grpc.internal' type=io.grpc.MethodDescriptor origin=null + TYPE_ARG Request: kotlin.String + TYPE_ARG Response: kotlin.Unit + ARG fullMethodName: CONST String type=kotlin.String value="BoxService/clientStream" + ARG requestCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.String + ARG responseCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG type: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:CLIENT_STREAMING' type=kotlinx.rpc.grpc.internal.MethodType + ARG schemaDescriptor: CONST Null type=kotlin.Any? value=null + ARG idempotent: CONST Boolean type=kotlin.Boolean value=true + ARG safe: CONST Boolean type=kotlin.Boolean value=true + ARG sampledToLocalTracing: CONST Boolean type=kotlin.Boolean value=true + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: io.grpc.MethodDescriptor<*, *> + ARG : CONST String type=kotlin.String value="serverStream" + ARG that: CALL 'public final fun methodDescriptor (fullMethodName: kotlin.String, requestCodec: kotlinx.rpc.grpc.codec.MessageCodec, responseCodec: kotlinx.rpc.grpc.codec.MessageCodec, type: kotlinx.rpc.grpc.internal.MethodType, schemaDescriptor: kotlin.Any?, idempotent: kotlin.Boolean, safe: kotlin.Boolean, sampledToLocalTracing: kotlin.Boolean): io.grpc.MethodDescriptor declared in kotlinx.rpc.grpc.internal' type=io.grpc.MethodDescriptor origin=null + TYPE_ARG Request: kotlin.Unit + TYPE_ARG Response: kotlin.Unit + ARG fullMethodName: CONST String type=kotlin.String value="BoxService/serverStream" + ARG requestCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG responseCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG type: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:SERVER_STREAMING' type=kotlinx.rpc.grpc.internal.MethodType + ARG schemaDescriptor: CONST Null type=kotlin.Any? value=null + ARG idempotent: CONST Boolean type=kotlin.Boolean value=true + ARG safe: CONST Boolean type=kotlin.Boolean value=true + ARG sampledToLocalTracing: CONST Boolean type=kotlin.Boolean value=true + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: io.grpc.MethodDescriptor<*, *> + ARG : CONST String type=kotlin.String value="bidiStream" + ARG that: CALL 'public final fun methodDescriptor (fullMethodName: kotlin.String, requestCodec: kotlinx.rpc.grpc.codec.MessageCodec, responseCodec: kotlinx.rpc.grpc.codec.MessageCodec, type: kotlinx.rpc.grpc.internal.MethodType, schemaDescriptor: kotlin.Any?, idempotent: kotlin.Boolean, safe: kotlin.Boolean, sampledToLocalTracing: kotlin.Boolean): io.grpc.MethodDescriptor declared in kotlinx.rpc.grpc.internal' type=io.grpc.MethodDescriptor origin=null + TYPE_ARG Request: kotlinx.rpc.codegen.test.Message + TYPE_ARG Response: kotlinx.rpc.codegen.test.Message + ARG fullMethodName: CONST String type=kotlin.String value="BoxService/bidiStream" + ARG requestCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlinx.rpc.codegen.test.Message + ARG responseCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlinx.rpc.codegen.test.Message + ARG type: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:BIDI_STREAMING' type=kotlinx.rpc.grpc.internal.MethodType + ARG schemaDescriptor: CONST Null type=kotlin.Any? value=null + ARG idempotent: CONST Boolean type=kotlin.Boolean value=true + ARG safe: CONST Boolean type=kotlin.Boolean value=true + ARG sampledToLocalTracing: CONST Boolean type=kotlin.Boolean value=true + CALL 'public final fun to (: A of kotlin.to, that: B of kotlin.to): kotlin.Pair declared in kotlin' type=kotlin.Pair> origin=null + TYPE_ARG A: kotlin.String + TYPE_ARG B: io.grpc.MethodDescriptor<*, *> + ARG : CONST String type=kotlin.String value="custom" + ARG that: CALL 'public final fun methodDescriptor (fullMethodName: kotlin.String, requestCodec: kotlinx.rpc.grpc.codec.MessageCodec, responseCodec: kotlinx.rpc.grpc.codec.MessageCodec, type: kotlinx.rpc.grpc.internal.MethodType, schemaDescriptor: kotlin.Any?, idempotent: kotlin.Boolean, safe: kotlin.Boolean, sampledToLocalTracing: kotlin.Boolean): io.grpc.MethodDescriptor declared in kotlinx.rpc.grpc.internal' type=io.grpc.MethodDescriptor.Custom> origin=null + TYPE_ARG Request: kotlin.Unit + TYPE_ARG Response: .Custom + ARG fullMethodName: CONST String type=kotlin.String value="BoxService/custom" + ARG requestCodec: CALL 'public abstract fun resolveOrNull (kType: kotlin.reflect.KType): kotlinx.rpc.grpc.codec.MessageCodec<*>? declared in kotlinx.rpc.grpc.codec.MessageCodecResolver' type=kotlinx.rpc.grpc.codec.MessageCodec origin=null + ARG : GET_VAR 'resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlinx.rpc.grpc.codec.MessageCodecResolver origin=null + ARG kType: CALL 'public final fun typeOf (): kotlin.reflect.KType declared in kotlin.reflect' type=kotlin.reflect.KType origin=null + TYPE_ARG T: kotlin.Unit + ARG responseCodec: GET_OBJECT 'CLASS OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.grpc.codec.MessageCodec<.Custom>]' type=.Custom.Companion + ARG type: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:UNARY' type=kotlinx.rpc.grpc.internal.MethodType + ARG schemaDescriptor: CONST Null type=kotlin.Any? value=null + ARG idempotent: CONST Boolean type=kotlin.Boolean value=true + ARG safe: CONST Boolean type=kotlin.Boolean value=true + ARG sampledToLocalTracing: CONST Boolean type=kotlin.Boolean value=true + VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:io.grpc.ServiceDescriptor [val] + CALL 'public final fun serviceDescriptor (name: kotlin.String, methods: kotlin.collections.Collection>, schemaDescriptor: kotlin.Any?): io.grpc.ServiceDescriptor declared in kotlinx.rpc.grpc.internal' type=io.grpc.ServiceDescriptor origin=null + ARG name: CONST String type=kotlin.String value="BoxService" + ARG methods: CALL 'public abstract fun (): kotlin.collections.Collection declared in kotlin.collections.Map' type=kotlin.collections.Collection origin=GET_PROPERTY + ARG : GET_VAR 'val tmp_0: kotlin.collections.Map> declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlin.collections.Map> origin=null + ARG schemaDescriptor: CONST Null type=kotlin.Any? value=null + RETURN type=kotlin.Nothing from='public final fun delegate (resolver: kotlinx.rpc.grpc.codec.MessageCodecResolver): kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .BoxService.$rpcServiceStub.Companion' + CONSTRUCTOR_CALL 'public constructor (methodDescriptorMap: kotlin.collections.Map>, serviceDescriptor: io.grpc.ServiceDescriptor) declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG methodDescriptorMap: GET_VAR 'val tmp_0: kotlin.collections.Map> declared in .BoxService.$rpcServiceStub.Companion.delegate' type=kotlin.collections.Map> origin=null + ARG serviceDescriptor: GET_VAR 'val tmp_1: io.grpc.ServiceDescriptor declared in .BoxService.$rpcServiceStub.Companion.delegate' type=io.grpc.ServiceDescriptor origin=null + FUN name:getCallable visibility:public modality:FINAL returnType:kotlinx.rpc.descriptor.RpcCallable? + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + VALUE_PARAMETER kind:Regular name:name index:1 type:kotlin.String + overridden: + public abstract fun getCallable (name: kotlin.String): kotlinx.rpc.descriptor.RpcCallable? declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun getCallable (name: kotlin.String): kotlinx.rpc.descriptor.RpcCallable? declared in .BoxService.$rpcServiceStub.Companion' + CALL 'public abstract fun get (key: K of kotlin.collections.Map): V of kotlin.collections.Map? declared in kotlin.collections.Map' type=kotlinx.rpc.descriptor.RpcCallable? origin=GET_ARRAY_ELEMENT + ARG : CALL 'private final fun (): kotlin.collections.Map.BoxService>> declared in .BoxService.$rpcServiceStub.Companion' type=kotlin.collections.Map.BoxService>> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.getCallable' type=.BoxService.$rpcServiceStub.Companion origin=null + ARG key: GET_VAR 'name: kotlin.String declared in .BoxService.$rpcServiceStub.Companion.getCallable' type=kotlin.String origin=null + PROPERTY name:callables visibility:public modality:FINAL [val] + overridden: + public abstract callables: kotlin.collections.Collection> declared in kotlinx.rpc.descriptor.RpcServiceDescriptor + FUN name: visibility:public modality:FINAL returnType:kotlin.collections.Collection.BoxService>> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub.Companion + correspondingProperty: PROPERTY name:callables visibility:public modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.collections.Collection.BoxService>> declared in .BoxService.$rpcServiceStub.Companion' + CALL 'public abstract fun (): kotlin.collections.Collection declared in kotlin.collections.Map' type=kotlin.collections.Collection origin=GET_PROPERTY + ARG : CALL 'private final fun (): kotlin.collections.Map.BoxService>> declared in .BoxService.$rpcServiceStub.Companion' type=kotlin.collections.Map.BoxService>> origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub.Companion declared in .BoxService.$rpcServiceStub.Companion.' type=.BoxService.$rpcServiceStub.Companion origin=null + CONSTRUCTOR visibility:public returnType:.BoxService.$rpcServiceStub [primary] + VALUE_PARAMETER kind:Regular name:__rpc_stub_id index:0 type:kotlin.Long + VALUE_PARAMETER kind:Regular name:__rpc_client index:1 type:kotlinx.rpc.RpcClient + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS GENERATED[kotlinx.rpc.codegen.RpcGeneratedStubKey] CLASS name:$rpcServiceStub modality:FINAL visibility:public superTypes:[.BoxService]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in .BoxService + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in .BoxService + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in .BoxService + FUN name:bidiStream visibility:public modality:OPEN returnType:kotlinx.coroutines.flow.Flow + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + VALUE_PARAMETER kind:Regular name:flow index:1 type:kotlinx.coroutines.flow.Flow + overridden: + public abstract fun bidiStream (flow: kotlinx.coroutines.flow.Flow): kotlinx.coroutines.flow.Flow declared in .BoxService + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun bidiStream (flow: kotlinx.coroutines.flow.Flow): kotlinx.coroutines.flow.Flow declared in .BoxService.$rpcServiceStub' + CALL 'public abstract fun callServerStreaming (call: kotlinx.rpc.RpcCall): kotlinx.coroutines.flow.Flow declared in kotlinx.rpc.RpcClient' type=kotlinx.coroutines.flow.Flow origin=null + TYPE_ARG T: kotlinx.coroutines.flow.Flow + ARG : CALL 'private final fun (): kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub' type=kotlinx.rpc.RpcClient origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.bidiStream' type=.BoxService.$rpcServiceStub origin=null + ARG call: CONSTRUCTOR_CALL 'public constructor (descriptor: kotlinx.rpc.descriptor.RpcServiceDescriptor<*>, callableName: kotlin.String, arguments: kotlin.Array, serviceId: kotlin.Long) declared in kotlinx.rpc.RpcCall' type=kotlinx.rpc.RpcCall origin=null + ARG descriptor: GET_OBJECT 'CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>]' type=.BoxService.$rpcServiceStub.Companion + ARG callableName: CONST String type=kotlin.String value="bidiStream" + ARG arguments: CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlin.Any? + ARG elements: VARARG type=kotlin.Array varargElementType=kotlin.Any? + GET_VAR 'flow: kotlinx.coroutines.flow.Flow declared in .BoxService.$rpcServiceStub.bidiStream' type=kotlinx.coroutines.flow.Flow origin=null + ARG serviceId: CALL 'private final fun (): kotlin.Long declared in .BoxService.$rpcServiceStub' type=kotlin.Long origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.bidiStream' type=.BoxService.$rpcServiceStub origin=null + FUN name:clientStream visibility:public modality:OPEN returnType:kotlin.Unit [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + VALUE_PARAMETER kind:Regular name:flow index:1 type:kotlinx.coroutines.flow.Flow + overridden: + public abstract fun clientStream (flow: kotlinx.coroutines.flow.Flow): kotlin.Unit declared in .BoxService + BLOCK_BODY + CALL 'public abstract fun call (call: kotlinx.rpc.RpcCall): T of kotlinx.rpc.RpcClient.call declared in kotlinx.rpc.RpcClient' type=kotlin.Unit origin=null + TYPE_ARG T: kotlin.Unit + ARG : CALL 'private final fun (): kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub' type=kotlinx.rpc.RpcClient origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.clientStream' type=.BoxService.$rpcServiceStub origin=null + ARG call: CONSTRUCTOR_CALL 'public constructor (descriptor: kotlinx.rpc.descriptor.RpcServiceDescriptor<*>, callableName: kotlin.String, arguments: kotlin.Array, serviceId: kotlin.Long) declared in kotlinx.rpc.RpcCall' type=kotlinx.rpc.RpcCall origin=null + ARG descriptor: GET_OBJECT 'CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>]' type=.BoxService.$rpcServiceStub.Companion + ARG callableName: CONST String type=kotlin.String value="clientStream" + ARG arguments: CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlin.Any? + ARG elements: VARARG type=kotlin.Array varargElementType=kotlin.Any? + GET_VAR 'flow: kotlinx.coroutines.flow.Flow declared in .BoxService.$rpcServiceStub.clientStream' type=kotlinx.coroutines.flow.Flow origin=null + ARG serviceId: CALL 'private final fun (): kotlin.Long declared in .BoxService.$rpcServiceStub' type=kotlin.Long origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.clientStream' type=.BoxService.$rpcServiceStub origin=null + FUN name:custom visibility:public modality:OPEN returnType:.Custom [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + overridden: + public abstract fun custom (): .Custom declared in .BoxService + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun custom (): .Custom declared in .BoxService.$rpcServiceStub' + CALL 'public abstract fun call (call: kotlinx.rpc.RpcCall): T of kotlinx.rpc.RpcClient.call declared in kotlinx.rpc.RpcClient' type=.Custom origin=null + TYPE_ARG T: .Custom + ARG : CALL 'private final fun (): kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub' type=kotlinx.rpc.RpcClient origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.custom' type=.BoxService.$rpcServiceStub origin=null + ARG call: CONSTRUCTOR_CALL 'public constructor (descriptor: kotlinx.rpc.descriptor.RpcServiceDescriptor<*>, callableName: kotlin.String, arguments: kotlin.Array, serviceId: kotlin.Long) declared in kotlinx.rpc.RpcCall' type=kotlinx.rpc.RpcCall origin=null + ARG descriptor: GET_OBJECT 'CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>]' type=.BoxService.$rpcServiceStub.Companion + ARG callableName: CONST String type=kotlin.String value="custom" + ARG arguments: CALL 'public final fun emptyArray (): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlin.Any? + ARG serviceId: CALL 'private final fun (): kotlin.Long declared in .BoxService.$rpcServiceStub' type=kotlin.Long origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.custom' type=.BoxService.$rpcServiceStub origin=null + FUN name:serverStream visibility:public modality:OPEN returnType:kotlinx.coroutines.flow.Flow + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + overridden: + public abstract fun serverStream (): kotlinx.coroutines.flow.Flow declared in .BoxService + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun serverStream (): kotlinx.coroutines.flow.Flow declared in .BoxService.$rpcServiceStub' + CALL 'public abstract fun callServerStreaming (call: kotlinx.rpc.RpcCall): kotlinx.coroutines.flow.Flow declared in kotlinx.rpc.RpcClient' type=kotlinx.coroutines.flow.Flow origin=null + TYPE_ARG T: kotlinx.coroutines.flow.Flow + ARG : CALL 'private final fun (): kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub' type=kotlinx.rpc.RpcClient origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.serverStream' type=.BoxService.$rpcServiceStub origin=null + ARG call: CONSTRUCTOR_CALL 'public constructor (descriptor: kotlinx.rpc.descriptor.RpcServiceDescriptor<*>, callableName: kotlin.String, arguments: kotlin.Array, serviceId: kotlin.Long) declared in kotlinx.rpc.RpcCall' type=kotlinx.rpc.RpcCall origin=null + ARG descriptor: GET_OBJECT 'CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>]' type=.BoxService.$rpcServiceStub.Companion + ARG callableName: CONST String type=kotlin.String value="serverStream" + ARG arguments: CALL 'public final fun emptyArray (): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlin.Any? + ARG serviceId: CALL 'private final fun (): kotlin.Long declared in .BoxService.$rpcServiceStub' type=kotlin.Long origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.serverStream' type=.BoxService.$rpcServiceStub origin=null + FUN name:simple visibility:public modality:OPEN returnType:kotlin.String [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + VALUE_PARAMETER kind:Regular name:value index:1 type:kotlin.String + overridden: + public abstract fun simple (value: kotlin.String): kotlin.String declared in .BoxService + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun simple (value: kotlin.String): kotlin.String declared in .BoxService.$rpcServiceStub' + CALL 'public abstract fun call (call: kotlinx.rpc.RpcCall): T of kotlinx.rpc.RpcClient.call declared in kotlinx.rpc.RpcClient' type=kotlin.String origin=null + TYPE_ARG T: kotlin.String + ARG : CALL 'private final fun (): kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub' type=kotlinx.rpc.RpcClient origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.simple' type=.BoxService.$rpcServiceStub origin=null + ARG call: CONSTRUCTOR_CALL 'public constructor (descriptor: kotlinx.rpc.descriptor.RpcServiceDescriptor<*>, callableName: kotlin.String, arguments: kotlin.Array, serviceId: kotlin.Long) declared in kotlinx.rpc.RpcCall' type=kotlinx.rpc.RpcCall origin=null + ARG descriptor: GET_OBJECT 'CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>]' type=.BoxService.$rpcServiceStub.Companion + ARG callableName: CONST String type=kotlin.String value="simple" + ARG arguments: CALL 'public final fun arrayOf (vararg elements: T of kotlin.arrayOf): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlin.Any? + ARG elements: VARARG type=kotlin.Array varargElementType=kotlin.Any? + GET_VAR 'value: kotlin.String declared in .BoxService.$rpcServiceStub.simple' type=kotlin.String origin=null + ARG serviceId: CALL 'private final fun (): kotlin.Long declared in .BoxService.$rpcServiceStub' type=kotlin.Long origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.simple' type=.BoxService.$rpcServiceStub origin=null + FUN name:unit visibility:public modality:OPEN returnType:kotlin.Unit [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService.$rpcServiceStub + overridden: + public abstract fun unit (): kotlin.Unit declared in .BoxService + BLOCK_BODY + CALL 'public abstract fun call (call: kotlinx.rpc.RpcCall): T of kotlinx.rpc.RpcClient.call declared in kotlinx.rpc.RpcClient' type=kotlin.Unit origin=null + TYPE_ARG T: kotlin.Unit + ARG : CALL 'private final fun (): kotlinx.rpc.RpcClient declared in .BoxService.$rpcServiceStub' type=kotlinx.rpc.RpcClient origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.unit' type=.BoxService.$rpcServiceStub origin=null + ARG call: CONSTRUCTOR_CALL 'public constructor (descriptor: kotlinx.rpc.descriptor.RpcServiceDescriptor<*>, callableName: kotlin.String, arguments: kotlin.Array, serviceId: kotlin.Long) declared in kotlinx.rpc.RpcCall' type=kotlinx.rpc.RpcCall origin=null + ARG descriptor: GET_OBJECT 'CLASS GENERATED[kotlinx.rpc.codegen.FirRpcServiceStubCompanionObject] OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[kotlinx.rpc.descriptor.RpcServiceDescriptor<.BoxService>; kotlinx.rpc.grpc.descriptor.GrpcServiceDescriptor<.BoxService>]' type=.BoxService.$rpcServiceStub.Companion + ARG callableName: CONST String type=kotlin.String value="unit" + ARG arguments: CALL 'public final fun emptyArray (): kotlin.Array declared in kotlin' type=kotlin.Array origin=null + TYPE_ARG T: kotlin.Any? + ARG serviceId: CALL 'private final fun (): kotlin.Long declared in .BoxService.$rpcServiceStub' type=kotlin.Long origin=GET_PROPERTY + ARG : GET_VAR ': .BoxService.$rpcServiceStub declared in .BoxService.$rpcServiceStub.unit' type=.BoxService.$rpcServiceStub origin=null + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + FUN name:bidiStream visibility:public modality:ABSTRACT returnType:kotlinx.coroutines.flow.Flow + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:flow index:1 type:kotlinx.coroutines.flow.Flow + FUN name:clientStream visibility:public modality:ABSTRACT returnType:kotlin.Unit [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:flow index:1 type:kotlinx.coroutines.flow.Flow + FUN name:custom visibility:public modality:ABSTRACT returnType:.Custom [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService + FUN name:serverStream visibility:public modality:ABSTRACT returnType:kotlinx.coroutines.flow.Flow + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService + FUN name:simple visibility:public modality:ABSTRACT returnType:kotlin.String [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService + VALUE_PARAMETER kind:Regular name:value index:1 type:kotlin.String + FUN name:unit visibility:public modality:ABSTRACT returnType:kotlin.Unit [suspend] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.BoxService + FUN name:box visibility:public modality:FINAL returnType:kotlin.String + BLOCK_BODY + VAR name:delegate type:kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate [val] + CALL 'public final fun grpcDelegate (): kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in kotlinx.rpc.codegen.test' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + TYPE_ARG T: .BoxService + WHEN type=kotlin.Unit origin=IF + BRANCH + if: CALL 'public final fun not (): kotlin.Boolean declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ + ARG : CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ + ARG arg0: CALL 'public open fun getName (): @[FlexibleNullability] kotlin.String? declared in io.grpc.ServiceDescriptor' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY + ARG : CALL 'public final fun (): io.grpc.ServiceDescriptor declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.ServiceDescriptor origin=GET_PROPERTY + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG arg1: CONST String type=kotlin.String value="BoxService" + then: BLOCK type=kotlin.Unit origin=null + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: Wrong service name: " + CALL 'public open fun getName (): @[FlexibleNullability] kotlin.String? declared in io.grpc.ServiceDescriptor' type=@[FlexibleNullability] kotlin.String? origin=GET_PROPERTY + ARG : CALL 'public final fun (): io.grpc.ServiceDescriptor declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.ServiceDescriptor origin=GET_PROPERTY + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Nothing? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_2 type:kotlin.String? [val] + CALL 'public final fun checkMethod (: io.grpc.MethodDescriptor<*, *>, expectedMethodName: kotlin.String, expectedMethodType: io.grpc.MethodDescriptor.MethodType, expectedServiceName: kotlin.String, expectedIsSafe: kotlin.Boolean, expectedIsIdempotent: kotlin.Boolean, expectedIsSampledToLocalTracing: kotlin.Boolean): kotlin.String? declared in kotlinx.rpc.codegen.test' type=kotlin.String? origin=null + ARG : CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): {T0 of kotlin.internal.ir.CHECK_NOT_NULL & Any} declared in kotlin.internal.ir' type=io.grpc.MethodDescriptor<*, *> origin=EXCLEXCL + TYPE_ARG T0: io.grpc.MethodDescriptor<*, *> + ARG arg0: CALL 'public final fun getMethodDescriptor (methodName: kotlin.String): io.grpc.MethodDescriptor<*, *>? declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.MethodDescriptor<*, *>? origin=null + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG methodName: CONST String type=kotlin.String value="simple" + ARG expectedMethodName: CONST String type=kotlin.String value="simple" + ARG expectedMethodType: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_JAVA_DECLARATION_STUB name:UNARY' type=io.grpc.MethodDescriptor.MethodType + ARG expectedServiceName: CONST String type=kotlin.String value="BoxService" + WHEN type=kotlin.Nothing? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + ARG arg0: GET_VAR 'val tmp_2: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public final fun let (: T of kotlin.let, block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Nothing origin=null + TYPE_ARG T: kotlin.String + TYPE_ARG R: kotlin.Nothing + ARG : GET_VAR 'val tmp_2: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Nothing + VALUE_PARAMETER kind:Regular name:it index:0 type:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: " + GET_VAR 'it: kotlin.String declared in .box.' type=kotlin.String origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Nothing? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_3 type:kotlin.String? [val] + CALL 'public final fun checkMethod (: io.grpc.MethodDescriptor<*, *>, expectedMethodName: kotlin.String, expectedMethodType: io.grpc.MethodDescriptor.MethodType, expectedServiceName: kotlin.String, expectedIsSafe: kotlin.Boolean, expectedIsIdempotent: kotlin.Boolean, expectedIsSampledToLocalTracing: kotlin.Boolean): kotlin.String? declared in kotlinx.rpc.codegen.test' type=kotlin.String? origin=null + ARG : CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): {T0 of kotlin.internal.ir.CHECK_NOT_NULL & Any} declared in kotlin.internal.ir' type=io.grpc.MethodDescriptor<*, *> origin=EXCLEXCL + TYPE_ARG T0: io.grpc.MethodDescriptor<*, *> + ARG arg0: CALL 'public final fun getMethodDescriptor (methodName: kotlin.String): io.grpc.MethodDescriptor<*, *>? declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.MethodDescriptor<*, *>? origin=null + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG methodName: CONST String type=kotlin.String value="unit" + ARG expectedMethodName: CONST String type=kotlin.String value="unit" + ARG expectedMethodType: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_JAVA_DECLARATION_STUB name:UNARY' type=io.grpc.MethodDescriptor.MethodType + ARG expectedServiceName: CONST String type=kotlin.String value="BoxService" + WHEN type=kotlin.Nothing? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + ARG arg0: GET_VAR 'val tmp_3: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public final fun let (: T of kotlin.let, block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Nothing origin=null + TYPE_ARG T: kotlin.String + TYPE_ARG R: kotlin.Nothing + ARG : GET_VAR 'val tmp_3: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Nothing + VALUE_PARAMETER kind:Regular name:it index:0 type:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: " + GET_VAR 'it: kotlin.String declared in .box.' type=kotlin.String origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Nothing? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_4 type:kotlin.String? [val] + CALL 'public final fun checkMethod (: io.grpc.MethodDescriptor<*, *>, expectedMethodName: kotlin.String, expectedMethodType: io.grpc.MethodDescriptor.MethodType, expectedServiceName: kotlin.String, expectedIsSafe: kotlin.Boolean, expectedIsIdempotent: kotlin.Boolean, expectedIsSampledToLocalTracing: kotlin.Boolean): kotlin.String? declared in kotlinx.rpc.codegen.test' type=kotlin.String? origin=null + ARG : CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): {T0 of kotlin.internal.ir.CHECK_NOT_NULL & Any} declared in kotlin.internal.ir' type=io.grpc.MethodDescriptor<*, *> origin=EXCLEXCL + TYPE_ARG T0: io.grpc.MethodDescriptor<*, *> + ARG arg0: CALL 'public final fun getMethodDescriptor (methodName: kotlin.String): io.grpc.MethodDescriptor<*, *>? declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.MethodDescriptor<*, *>? origin=null + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG methodName: CONST String type=kotlin.String value="custom" + ARG expectedMethodName: CONST String type=kotlin.String value="custom" + ARG expectedMethodType: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_JAVA_DECLARATION_STUB name:UNARY' type=io.grpc.MethodDescriptor.MethodType + ARG expectedServiceName: CONST String type=kotlin.String value="BoxService" + WHEN type=kotlin.Nothing? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + ARG arg0: GET_VAR 'val tmp_4: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public final fun let (: T of kotlin.let, block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Nothing origin=null + TYPE_ARG T: kotlin.String + TYPE_ARG R: kotlin.Nothing + ARG : GET_VAR 'val tmp_4: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Nothing + VALUE_PARAMETER kind:Regular name:it index:0 type:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: " + GET_VAR 'it: kotlin.String declared in .box.' type=kotlin.String origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Nothing? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_5 type:kotlin.String? [val] + CALL 'public final fun checkMethod (: io.grpc.MethodDescriptor<*, *>, expectedMethodName: kotlin.String, expectedMethodType: io.grpc.MethodDescriptor.MethodType, expectedServiceName: kotlin.String, expectedIsSafe: kotlin.Boolean, expectedIsIdempotent: kotlin.Boolean, expectedIsSampledToLocalTracing: kotlin.Boolean): kotlin.String? declared in kotlinx.rpc.codegen.test' type=kotlin.String? origin=null + ARG : CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): {T0 of kotlin.internal.ir.CHECK_NOT_NULL & Any} declared in kotlin.internal.ir' type=io.grpc.MethodDescriptor<*, *> origin=EXCLEXCL + TYPE_ARG T0: io.grpc.MethodDescriptor<*, *> + ARG arg0: CALL 'public final fun getMethodDescriptor (methodName: kotlin.String): io.grpc.MethodDescriptor<*, *>? declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.MethodDescriptor<*, *>? origin=null + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG methodName: CONST String type=kotlin.String value="clientStream" + ARG expectedMethodName: CONST String type=kotlin.String value="clientStream" + ARG expectedMethodType: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_JAVA_DECLARATION_STUB name:CLIENT_STREAMING' type=io.grpc.MethodDescriptor.MethodType + ARG expectedServiceName: CONST String type=kotlin.String value="BoxService" + WHEN type=kotlin.Nothing? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + ARG arg0: GET_VAR 'val tmp_5: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public final fun let (: T of kotlin.let, block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Nothing origin=null + TYPE_ARG T: kotlin.String + TYPE_ARG R: kotlin.Nothing + ARG : GET_VAR 'val tmp_5: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Nothing + VALUE_PARAMETER kind:Regular name:it index:0 type:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: " + GET_VAR 'it: kotlin.String declared in .box.' type=kotlin.String origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Nothing? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_6 type:kotlin.String? [val] + CALL 'public final fun checkMethod (: io.grpc.MethodDescriptor<*, *>, expectedMethodName: kotlin.String, expectedMethodType: io.grpc.MethodDescriptor.MethodType, expectedServiceName: kotlin.String, expectedIsSafe: kotlin.Boolean, expectedIsIdempotent: kotlin.Boolean, expectedIsSampledToLocalTracing: kotlin.Boolean): kotlin.String? declared in kotlinx.rpc.codegen.test' type=kotlin.String? origin=null + ARG : CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): {T0 of kotlin.internal.ir.CHECK_NOT_NULL & Any} declared in kotlin.internal.ir' type=io.grpc.MethodDescriptor<*, *> origin=EXCLEXCL + TYPE_ARG T0: io.grpc.MethodDescriptor<*, *> + ARG arg0: CALL 'public final fun getMethodDescriptor (methodName: kotlin.String): io.grpc.MethodDescriptor<*, *>? declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.MethodDescriptor<*, *>? origin=null + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG methodName: CONST String type=kotlin.String value="serverStream" + ARG expectedMethodName: CONST String type=kotlin.String value="serverStream" + ARG expectedMethodType: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_JAVA_DECLARATION_STUB name:SERVER_STREAMING' type=io.grpc.MethodDescriptor.MethodType + ARG expectedServiceName: CONST String type=kotlin.String value="BoxService" + WHEN type=kotlin.Nothing? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + ARG arg0: GET_VAR 'val tmp_6: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public final fun let (: T of kotlin.let, block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Nothing origin=null + TYPE_ARG T: kotlin.String + TYPE_ARG R: kotlin.Nothing + ARG : GET_VAR 'val tmp_6: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Nothing + VALUE_PARAMETER kind:Regular name:it index:0 type:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: " + GET_VAR 'it: kotlin.String declared in .box.' type=kotlin.String origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Nothing? origin=SAFE_CALL + VAR IR_TEMPORARY_VARIABLE name:tmp_7 type:kotlin.String? [val] + CALL 'public final fun checkMethod (: io.grpc.MethodDescriptor<*, *>, expectedMethodName: kotlin.String, expectedMethodType: io.grpc.MethodDescriptor.MethodType, expectedServiceName: kotlin.String, expectedIsSafe: kotlin.Boolean, expectedIsIdempotent: kotlin.Boolean, expectedIsSampledToLocalTracing: kotlin.Boolean): kotlin.String? declared in kotlinx.rpc.codegen.test' type=kotlin.String? origin=null + ARG : CALL 'public final fun CHECK_NOT_NULL (arg0: T0 of kotlin.internal.ir.CHECK_NOT_NULL?): {T0 of kotlin.internal.ir.CHECK_NOT_NULL & Any} declared in kotlin.internal.ir' type=io.grpc.MethodDescriptor<*, *> origin=EXCLEXCL + TYPE_ARG T0: io.grpc.MethodDescriptor<*, *> + ARG arg0: CALL 'public final fun getMethodDescriptor (methodName: kotlin.String): io.grpc.MethodDescriptor<*, *>? declared in kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate' type=io.grpc.MethodDescriptor<*, *>? origin=null + ARG : GET_VAR 'val delegate: kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate declared in .box' type=kotlinx.rpc.grpc.descriptor.GrpcServiceDelegate origin=null + ARG methodName: CONST String type=kotlin.String value="bidiStream" + ARG expectedMethodName: CONST String type=kotlin.String value="bidiStream" + ARG expectedMethodType: GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_JAVA_DECLARATION_STUB name:BIDI_STREAMING' type=io.grpc.MethodDescriptor.MethodType + ARG expectedServiceName: CONST String type=kotlin.String value="BoxService" + WHEN type=kotlin.Nothing? origin=null + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + ARG arg0: GET_VAR 'val tmp_7: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG arg1: CONST Null type=kotlin.Nothing? value=null + then: CONST Null type=kotlin.Nothing? value=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CALL 'public final fun let (: T of kotlin.let, block: kotlin.Function1): R of kotlin.let declared in kotlin' type=kotlin.Nothing origin=null + TYPE_ARG T: kotlin.String + TYPE_ARG R: kotlin.Nothing + ARG : GET_VAR 'val tmp_7: kotlin.String? declared in .box' type=kotlin.String? origin=null + ARG block: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Nothing + VALUE_PARAMETER kind:Regular name:it index:0 type:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="Fail: " + GET_VAR 'it: kotlin.String declared in .box.' type=kotlin.String origin=null + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + CONST String type=kotlin.String value="OK" diff --git a/tests/compiler-plugin-tests/src/testData/box/grpc.fir.txt b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.txt new file mode 100644 index 000000000..36a642e84 --- /dev/null +++ b/tests/compiler-plugin-tests/src/testData/box/grpc.fir.txt @@ -0,0 +1,80 @@ +FILE: grpc.kt + @FILE:R|kotlin/OptIn|(markerClass = vararg((Q|kotlinx/rpc/internal/utils/ExperimentalRpcApi|), (Q|kotlinx/rpc/internal/utils/InternalRpcApi|))) + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|Custom.Companion|)) public final class Custom : R|kotlin/Any| { + public constructor(content: R|kotlin/String|): R|Custom| { + super() + } + + public final val content: R|kotlin/String| = R|/content| + public get(): R|kotlin/String| + + public final companion object Companion : R|kotlinx/rpc/grpc/codec/MessageCodec| { + private constructor(): R|Custom.Companion| { + super() + } + + public open override fun encode(value: R|Custom|): R|kotlinx/io/Source| { + R|kotlin/TODO|(String(Not yet implemented)) + } + + public open override fun decode(stream: R|kotlinx/io/Source|): R|Custom| { + R|kotlin/TODO|(String(Not yet implemented)) + } + + } + + } + @R|kotlinx/rpc/grpc/annotations/Grpc|() public abstract interface BoxService : R|kotlin/Any| { + public abstract suspend fun simple(value: R|kotlin/String|): R|kotlin/String| + + public abstract suspend fun unit(): R|kotlin/Unit| + + public abstract suspend fun clientStream(flow: R|kotlinx/coroutines/flow/Flow|): R|kotlin/Unit| + + public abstract fun serverStream(): R|kotlinx/coroutines/flow/Flow| + + public abstract fun bidiStream(flow: R|kotlinx/coroutines/flow/Flow|): R|kotlinx/coroutines/flow/Flow| + + public abstract suspend fun custom(): R|Custom| + + public final class $rpcServiceStub : R|kotlin/Any| { + public final companion object Companion : R|kotlin/Any| { + } + + } + + } + public final fun box(): R|kotlin/String| { + lval delegate: R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate| = R|kotlinx/rpc/codegen/test/grpcDelegate|() + when () { + !=(R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.serviceDescriptor|.R|io/grpc/ServiceDescriptor.name|, String(BoxService)) -> { + ^box (String(Fail: Wrong service name: ), R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.serviceDescriptor|.R|io/grpc/ServiceDescriptor.name|) + } + } + + R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.getMethodDescriptor|(String(simple))!!.R|kotlinx/rpc/codegen/test/checkMethod|(String(simple), Q|io/grpc/MethodDescriptor.MethodType|.R|io/grpc/MethodDescriptor.MethodType.UNARY|, String(BoxService))?.{ $subj$.R|kotlin/let|( = let@fun (it: R|kotlin/String|): R|kotlin/Nothing| { + ^box (String(Fail: ), R|/it|) + } + ) } + R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.getMethodDescriptor|(String(unit))!!.R|kotlinx/rpc/codegen/test/checkMethod|(String(unit), Q|io/grpc/MethodDescriptor.MethodType|.R|io/grpc/MethodDescriptor.MethodType.UNARY|, String(BoxService))?.{ $subj$.R|kotlin/let|( = let@fun (it: R|kotlin/String|): R|kotlin/Nothing| { + ^box (String(Fail: ), R|/it|) + } + ) } + R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.getMethodDescriptor|(String(custom))!!.R|kotlinx/rpc/codegen/test/checkMethod|(String(custom), Q|io/grpc/MethodDescriptor.MethodType|.R|io/grpc/MethodDescriptor.MethodType.UNARY|, String(BoxService))?.{ $subj$.R|kotlin/let|( = let@fun (it: R|kotlin/String|): R|kotlin/Nothing| { + ^box (String(Fail: ), R|/it|) + } + ) } + R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.getMethodDescriptor|(String(clientStream))!!.R|kotlinx/rpc/codegen/test/checkMethod|(String(clientStream), Q|io/grpc/MethodDescriptor.MethodType|.R|io/grpc/MethodDescriptor.MethodType.CLIENT_STREAMING|, String(BoxService))?.{ $subj$.R|kotlin/let|( = let@fun (it: R|kotlin/String|): R|kotlin/Nothing| { + ^box (String(Fail: ), R|/it|) + } + ) } + R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.getMethodDescriptor|(String(serverStream))!!.R|kotlinx/rpc/codegen/test/checkMethod|(String(serverStream), Q|io/grpc/MethodDescriptor.MethodType|.R|io/grpc/MethodDescriptor.MethodType.SERVER_STREAMING|, String(BoxService))?.{ $subj$.R|kotlin/let|( = let@fun (it: R|kotlin/String|): R|kotlin/Nothing| { + ^box (String(Fail: ), R|/it|) + } + ) } + R|/delegate|.R|kotlinx/rpc/grpc/descriptor/GrpcServiceDelegate.getMethodDescriptor|(String(bidiStream))!!.R|kotlinx/rpc/codegen/test/checkMethod|(String(bidiStream), Q|io/grpc/MethodDescriptor.MethodType|.R|io/grpc/MethodDescriptor.MethodType.BIDI_STREAMING|, String(BoxService))?.{ $subj$.R|kotlin/let|( = let@fun (it: R|kotlin/String|): R|kotlin/Nothing| { + ^box (String(Fail: ), R|/it|) + } + ) } + ^box String(OK) + } diff --git a/tests/compiler-plugin-tests/src/testData/box/grpc.kt b/tests/compiler-plugin-tests/src/testData/box/grpc.kt new file mode 100644 index 000000000..7ce58d401 --- /dev/null +++ b/tests/compiler-plugin-tests/src/testData/box/grpc.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +// RUN_PIPELINE_TILL: BACKEND + +@file:OptIn(kotlinx.rpc.internal.utils.ExperimentalRpcApi::class, kotlinx.rpc.internal.utils.InternalRpcApi::class) + +import io.grpc.MethodDescriptor +import kotlinx.io.Source +import kotlinx.coroutines.flow.Flow +import kotlinx.rpc.codegen.test.grpcDelegate +import kotlinx.rpc.codegen.test.checkMethod +import kotlinx.rpc.codegen.test.Message +import kotlinx.rpc.grpc.annotations.Grpc +import kotlinx.rpc.grpc.codec.WithCodec +import kotlinx.rpc.grpc.codec.MessageCodec + +@WithCodec(Custom.Companion::class) +class Custom(val content: String) { + companion object : MessageCodec { + override fun encode(value: Custom): Source { + TODO("Not yet implemented") + } + + override fun decode(stream: Source): Custom { + TODO("Not yet implemented") + } + } +} + +@Grpc +interface BoxService { + suspend fun simple(value: String): String + + suspend fun unit() + + suspend fun clientStream(flow: Flow) + + fun serverStream(): Flow + + fun bidiStream(flow: Flow): Flow + + suspend fun custom(): Custom +} + +fun box(): String { + val delegate = grpcDelegate() + + if (delegate.serviceDescriptor.name != "BoxService") { + return "Fail: Wrong service name: ${delegate.serviceDescriptor.name}" + } + + delegate.getMethodDescriptor("simple")!!.checkMethod( + expectedMethodName = "simple", + expectedMethodType = MethodDescriptor.MethodType.UNARY, + expectedServiceName = "BoxService", + )?.let { return "Fail: $it"} + + delegate.getMethodDescriptor("unit")!!.checkMethod( + expectedMethodName = "unit", + expectedMethodType = MethodDescriptor.MethodType.UNARY, + expectedServiceName = "BoxService", + )?.let { return "Fail: $it"} + + delegate.getMethodDescriptor("custom")!!.checkMethod( + expectedMethodName = "custom", + expectedMethodType = MethodDescriptor.MethodType.UNARY, + expectedServiceName = "BoxService", + )?.let { return "Fail: $it"} + + delegate.getMethodDescriptor("clientStream")!!.checkMethod( + expectedMethodName = "clientStream", + expectedMethodType = MethodDescriptor.MethodType.CLIENT_STREAMING, + expectedServiceName = "BoxService", + )?.let { return "Fail: $it"} + + delegate.getMethodDescriptor("serverStream")!!.checkMethod( + expectedMethodName = "serverStream", + expectedMethodType = MethodDescriptor.MethodType.SERVER_STREAMING, + expectedServiceName = "BoxService", + )?.let { return "Fail: $it"} + + delegate.getMethodDescriptor("bidiStream")!!.checkMethod( + expectedMethodName = "bidiStream", + expectedMethodType = MethodDescriptor.MethodType.BIDI_STREAMING, + expectedServiceName = "BoxService", + )?.let { return "Fail: $it"} + + return "OK" +} diff --git a/tests/compiler-plugin-tests/src/testData/diagnostics/grpc.fir.txt b/tests/compiler-plugin-tests/src/testData/diagnostics/grpc.fir.txt new file mode 100644 index 000000000..ed5d4d888 --- /dev/null +++ b/tests/compiler-plugin-tests/src/testData/diagnostics/grpc.fir.txt @@ -0,0 +1,36 @@ +FILE: module_main_grpc.kt + @R|kotlinx/rpc/grpc/annotations/Grpc|() public abstract interface MyService : R|kotlin/Any| { + public abstract suspend fun unary(value: R|kotlin/String|): R|kotlin/String| + + public abstract suspend fun clientStreaming(flow: R|kotlinx/coroutines/flow/Flow|): R|kotlin/String| + + public abstract fun serverStreaming(value: R|kotlin/String|): R|kotlinx/coroutines/flow/Flow| + + public abstract fun bidiStreaming(flow: R|kotlinx/coroutines/flow/Flow|): R|kotlinx/coroutines/flow/Flow| + + public abstract suspend fun zeroValues(): R|kotlin/Unit| + + public abstract fun checkRegularDiagnosticsWork(): R|kotlin/Unit| + + public abstract suspend fun multipleParams(param1: R|kotlin/String|, param2: R|kotlin/String|): R|kotlin/Unit| + + public abstract suspend fun nullable(param1: R|kotlin/String?|): R|kotlin/String?| + + public abstract suspend fun innerFlow(withFlow: R|WithFlow|): R|kotlin/Unit| + + public final class $rpcServiceStub : R|kotlin/Any| { + public final companion object Companion : R|kotlin/Any| { + } + + } + + } + public final class WithFlow : R|kotlin/Any| { + public constructor(flow: R|kotlinx/coroutines/flow/Flow|): R|WithFlow| { + super() + } + + public final val flow: R|kotlinx/coroutines/flow/Flow| = R|/flow| + public get(): R|kotlinx/coroutines/flow/Flow| + + } diff --git a/tests/compiler-plugin-tests/src/testData/diagnostics/grpc.kt b/tests/compiler-plugin-tests/src/testData/diagnostics/grpc.kt new file mode 100644 index 000000000..d3870af4d --- /dev/null +++ b/tests/compiler-plugin-tests/src/testData/diagnostics/grpc.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +// RUN_PIPELINE_TILL: FRONTEND + +// MODULE: main + +import kotlinx.rpc.grpc.annotations.Grpc +import kotlinx.coroutines.flow.Flow + +@Grpc +interface MyService { + suspend fun unary(value: String): String + + suspend fun clientStreaming(flow: Flow): String + + fun serverStreaming(value: String): Flow + + fun bidiStreaming(flow: Flow): Flow + + suspend fun zeroValues() + + fun checkRegularDiagnosticsWork() + + suspend fun multipleParams(param1: String, param2: String) + + suspend fun nullable(param1: String?): String? + + suspend fun innerFlow(withFlow: WithFlow) +} + +class WithFlow(val flow: Flow) diff --git a/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.fir.txt b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.fir.txt new file mode 100644 index 000000000..be8efe558 --- /dev/null +++ b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.fir.txt @@ -0,0 +1,88 @@ +FILE: module_main_withCodec.kt + @FILE:R|kotlin/OptIn|(markerClass = vararg((Q|kotlinx/rpc/internal/utils/ExperimentalRpcApi|))) + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec|)) public open class Test : R|kotlin/Any| { + public constructor(): R|Test| { + super() + } + + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec|)) public final class Test1 : R|kotlin/Any| { + public constructor(): R|Test1| { + super() + } + + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec|)) public final class Test2 : R|Test| { + public constructor(): R|Test2| { + super() + } + + } + public final object TestCodec : R|kotlinx/rpc/grpc/codec/MessageCodec| { + private constructor(): R|TestCodec| { + super() + } + + public open override fun encode(value: R|Test|): R|kotlinx/io/Source| { + R|kotlin/error|(String(Not implemented)) + } + + public open override fun decode(stream: R|kotlinx/io/Source|): R|Test| { + R|kotlin/error|(String(Not implemented)) + } + + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec3|)) public final class Test3 : R|kotlin/Any| { + public constructor(): R|Test3| { + super() + } + + } + public final class TestCodec3 : R|kotlinx/rpc/grpc/codec/MessageCodec| { + public constructor(): R|TestCodec3| { + super() + } + + public open override fun encode(value: R|Test3|): R|kotlinx/io/Source| { + R|kotlin/error|(String(Not implemented)) + } + + public open override fun decode(stream: R|kotlinx/io/Source|): R|Test3| { + R|kotlin/error|(String(Not implemented)) + } + + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec4|)) public final class Test4 : R|kotlin/Any| { + public constructor(): R|Test4| { + super() + } + + } + public final object TestCodec4 : R|ATestCodec4|, R|Whatever| { + private constructor(): R|TestCodec4| { + super() + } + + } + public abstract interface Whatever : R|kotlin/Any| { + } + public abstract class ATestCodec4 : R|kotlinx/rpc/grpc/codec/MessageCodec| { + public constructor(): R|ATestCodec4| { + super() + } + + public open override fun encode(value: R|Test4|): R|kotlinx/io/Source| { + R|kotlin/error|(String(Not implemented)) + } + + public open override fun decode(stream: R|kotlinx/io/Source|): R|Test4| { + R|kotlin/error|(String(Not implemented)) + } + + } + @R|kotlinx/rpc/grpc/codec/WithCodec|(codec = (Q|TestCodec4|)) public final class Test5 : R|kotlin/Any| { + public constructor(): R|Test5| { + super() + } + + } diff --git a/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.kt b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.kt new file mode 100644 index 000000000..2307e49f7 --- /dev/null +++ b/tests/compiler-plugin-tests/src/testData/diagnostics/withCodec.kt @@ -0,0 +1,65 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +// RUN_PIPELINE_TILL: FRONTEND + +// MODULE: main + +@file:OptIn(kotlinx.rpc.internal.utils.ExperimentalRpcApi::class) + +import kotlinx.rpc.grpc.codec.WithCodec +import kotlinx.rpc.grpc.codec.MessageCodec +import kotlinx.io.Source + +@WithCodec(TestCodec::class) +open class Test + +@WithCodec(TestCodec::class) +class Test1 + +@WithCodec(TestCodec::class) +class Test2 : Test() + +object TestCodec : MessageCodec { + override fun encode(value: Test): Source { + error("Not implemented") + } + + override fun decode(stream: Source): Test { + error("Not implemented") + } +} + +@WithCodec(TestCodec3::class) +class Test3 + +class TestCodec3 : MessageCodec { + override fun encode(value: Test3): Source { + error("Not implemented") + } + + override fun decode(stream: Source): Test3 { + error("Not implemented") + } +} + +@WithCodec(TestCodec4::class) +class Test4 + +object TestCodec4 : ATestCodec4(), Whatever + +interface Whatever + +abstract class ATestCodec4 : MessageCodec { + override fun encode(value: Test4): Source { + error("Not implemented") + } + + override fun decode(stream: Source): Test4 { + error("Not implemented") + } +} + +@WithCodec(TestCodec4::class) +class Test5