From 155777e3fa8f0d17f9f897c1b4895796179e438d Mon Sep 17 00:00:00 2001 From: Alexander Korepanov Date: Wed, 4 Jan 2023 17:06:26 +0100 Subject: [PATCH] [JS IR] Detect broken cross-module references The patch adds an error if the module can not find the cross-module reference. The patch removes the DCE optimization which eliminates implement() intrinsic, because it leads to a broken cross-module reference and broken JS code with implement() call, albeit in an unreachable block. --- .../js/dce/JsUsefulDeclarationProcessor.kt | 9 +- .../ir/backend/js/ic/JsMultiModuleCache.kt | 20 ++- .../irToJs/IrModuleToJsTransformer.kt | 6 + .../irToJs/JsIrProgramFragment.kt | 28 +++- .../serialization/JsIrAstDeserializer.kt | 2 + .../utils/serialization/JsIrAstSerializer.kt | 4 + .../FunctionalInterfacesUtils.kt | 9 + .../serialization/IrModuleDeserializer.kt | 8 - js/js.serializer/src/js-ast.proto | 3 +- .../serialization/js/ast/JsAstProtoBuf.java | 155 ++++++++++++++++++ 10 files changed, 219 insertions(+), 25 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/JsUsefulDeclarationProcessor.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/JsUsefulDeclarationProcessor.kt index 92860e2f49a..d00876dd283 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/JsUsefulDeclarationProcessor.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/dce/JsUsefulDeclarationProcessor.kt @@ -27,13 +27,6 @@ internal class JsUsefulDeclarationProcessor( private val hashCodeMethod = getMethodOfAny("hashCode") override val bodyVisitor: BodyVisitorBase = object : BodyVisitorBase() { - override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: IrDeclaration) { - if (expression.symbol != context.intrinsics.implementSymbol) { - // Just ignore implement to not include large chunk of code inside small applications if it's not needed - super.visitFunctionAccess(expression, data) - } - } - override fun visitCall(expression: IrCall, data: IrDeclaration) { super.visitCall(expression, data) when (expression.symbol) { @@ -259,4 +252,4 @@ private fun Collection.filterDescendantsOf(bases: Collection): } return this.filter { overridesAnyBase(it) } -} \ No newline at end of file +} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt index 25f9a5080e0..8de3b97d195 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/JsMultiModuleCache.kt @@ -20,7 +20,7 @@ class JsMultiModuleCache(private val moduleArtifacts: List) { } private enum class NameType(val typeMask: Int) { - DEFINITIONS(0b01), NAME_BINDINGS(0b10) + DEFINITIONS(0b1), NAME_BINDINGS(0b10), OPTIONAL_IMPORTS(0b100) } class CachedModuleInfo(val artifact: ModuleArtifact, val jsIrHeader: JsIrModuleHeader, var crossModuleReferencesHash: ICHash = ICHash()) @@ -30,6 +30,7 @@ class JsMultiModuleCache(private val moduleArtifacts: List) { private fun ModuleArtifact.fetchModuleInfo() = File(artifactsDir, JS_MODULE_HEADER).useCodedInputIfExists { val definitions = mutableSetOf() val nameBindings = mutableMapOf() + val optionalCrossModuleImports = hashSetOf() val crossModuleReferencesHash = ICHash.fromProtoStream(this) val hasJsExports = readBool() @@ -39,13 +40,24 @@ class JsMultiModuleCache(private val moduleArtifacts: List) { if (mask and NameType.DEFINITIONS.typeMask != 0) { definitions += tag } + if (mask and NameType.OPTIONAL_IMPORTS.typeMask != 0) { + optionalCrossModuleImports += tag + } if (mask and NameType.NAME_BINDINGS.typeMask != 0) { nameBindings[tag] = readString() } } CachedModuleInfo( artifact = this@fetchModuleInfo, - jsIrHeader = JsIrModuleHeader(moduleSafeName, moduleExternalName, definitions, nameBindings, hasJsExports, null), + jsIrHeader = JsIrModuleHeader( + moduleName = moduleSafeName, + externalModuleName = moduleExternalName, + definitions = definitions, + nameBindings = nameBindings, + optionalCrossModuleImports = optionalCrossModuleImports, + hasJsExports = hasJsExports, + associatedModule = null + ), crossModuleReferencesHash = crossModuleReferencesHash ) } @@ -56,6 +68,10 @@ class JsMultiModuleCache(private val moduleArtifacts: List) { for ((tag, name) in jsIrHeader.nameBindings) { names[tag] = NameType.NAME_BINDINGS.typeMask to name } + for (tag in jsIrHeader.optionalCrossModuleImports) { + val maskAndName = names[tag] + names[tag] = ((maskAndName?.first ?: 0) or NameType.OPTIONAL_IMPORTS.typeMask) to maskAndName?.second + } for (tag in jsIrHeader.definitions) { val maskAndName = names[tag] names[tag] = ((maskAndName?.first ?: 0) or NameType.DEFINITIONS.typeMask) to maskAndName?.second diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index 4ffc0ecd3f0..0a01ee7ee67 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs +import org.jetbrains.kotlin.backend.common.serialization.checkIsFunctionInterface import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.ir.backend.js.* import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations import org.jetbrains.kotlin.ir.backend.js.export.* import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering +import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.isInterface @@ -321,12 +323,16 @@ class IrModuleToJsTransformer( nameGenerator.nameMap.entries.forEach { (declaration, name) -> computeTag(declaration)?.let { tag -> result.nameBindings[tag] = name + if (isBuiltInClass(declaration) || checkIsFunctionInterface(declaration.symbol.signature)) { + result.optionalCrossModuleImports += tag + } } } nameGenerator.imports.entries.forEach { (declaration, importExpression) -> val tag = computeTag(declaration) ?: error("No tag for imported declaration ${declaration.render()}") result.imports[tag] = importExpression + result.optionalCrossModuleImports += tag } fileExports.file.declarations.forEach { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt index 84dfc664603..ec65d909e64 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIrProgramFragment.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind class JsIrProgramFragment(val packageFqn: String) { val nameBindings = mutableMapOf() + val optionalCrossModuleImports = hashSetOf() val declarations = JsCompositeBlock() val exports = JsCompositeBlock() val importedModules = mutableListOf() @@ -35,6 +36,7 @@ class JsIrModule( fun makeModuleHeader(): JsIrModuleHeader { val nameBindings = mutableMapOf() val definitions = mutableSetOf() + val optionalCrossModuleImports = hashSetOf() var hasJsExports = false for (fragment in fragments) { hasJsExports = hasJsExports || !fragment.exports.isEmpty @@ -42,8 +44,17 @@ class JsIrModule( nameBindings[tag] = name.toString() } definitions += fragment.definitions + optionalCrossModuleImports += fragment.optionalCrossModuleImports } - return JsIrModuleHeader(moduleName, externalModuleName, definitions, nameBindings, hasJsExports, this) + return JsIrModuleHeader( + moduleName = moduleName, + externalModuleName = externalModuleName, + definitions = definitions, + nameBindings = nameBindings, + optionalCrossModuleImports = optionalCrossModuleImports, + hasJsExports = hasJsExports, + associatedModule = this + ) } } @@ -52,6 +63,7 @@ class JsIrModuleHeader( val externalModuleName: String, val definitions: Set, val nameBindings: Map, + val optionalCrossModuleImports: Set, val hasJsExports: Boolean, var associatedModule: JsIrModule? ) { @@ -100,7 +112,13 @@ class CrossModuleDependenciesResolver( for (header in headers) { val builder = headerToBuilder[header]!! for (tag in header.externalNames) { - val fromModuleBuilder = definitionModule[tag] ?: continue // TODO error? + val fromModuleBuilder = definitionModule[tag] + if (fromModuleBuilder == null) { + if (tag in header.optionalCrossModuleImports) { + continue + } + error("Internal error: cannot find external signature '$tag' for module ${header.moduleName}") + } builder.imports += CrossModuleRef(fromModuleBuilder, tag) fromModuleBuilder.exports += tag @@ -111,8 +129,6 @@ class CrossModuleDependenciesResolver( } } -private fun String.prettyTag() = takeWhile { c -> c != '|' } - private class CrossModuleRef(val module: JsIrModuleCrossModuleReferecenceBuilder, val tag: String) private class JsIrModuleCrossModuleReferecenceBuilder( @@ -153,7 +169,7 @@ private class JsIrModuleCrossModuleReferecenceBuilder( val tag = crossModuleRef.tag require(crossModuleRef.module::exportNames.isInitialized) { // This situation appears in case of a dependent module redefine a symbol (function) from their dependency - "Cross module dependency resolution failed due to symbol '${tag.prettyTag()}' redefinition" + "Cross module dependency resolution failed due to signature '$tag' redefinition" } val exportedAs = crossModuleRef.module.exportNames[tag]!! val moduleName = import(crossModuleRef.module.header) @@ -207,7 +223,7 @@ class CrossModuleReferences( fun initJsImportsForModule(module: JsIrModule) { val tagToName = module.fragments.flatMap { it.nameBindings.entries }.associate { it.key to it.value } jsImports = imports.entries.associate { - val importedAs = tagToName[it.key] ?: error("Internal error: cannot find imported name for symbol ${it.key.prettyTag()}") + val importedAs = tagToName[it.key] ?: error("Internal error: cannot find imported name for signature ${it.key}") val exportRef = JsNameRef( it.value.exportedAs, it.value.moduleExporter.let { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt index 85fd95de809..e369e5e8423 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstDeserializer.kt @@ -68,6 +68,8 @@ class JsIrAstDeserializer : JsAstDeserializerBase() { deserializeString(nameBindingProto.signatureId) to deserializeName(nameBindingProto.nameId) } + proto.optionalCrossModuleImportsList.mapTo(fragment.optionalCrossModuleImports) { deserializeString(it) } + proto.irClassModelList.associateTo(fragment.classes) { clsProto -> deserialize(clsProto) } if (proto.hasTestsInvocation()) { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt index 6166d9af54d..0219bc349a0 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/serialization/JsIrAstSerializer.kt @@ -70,6 +70,10 @@ class JsIrAstSerializer: JsAstSerializerBase() { fragmentBuilder.addNameBinding(nameBindingBuilder) } + fragment.optionalCrossModuleImports.forEach { + fragmentBuilder.addOptionalCrossModuleImports(serialize(it)) + } + fragment.classes.entries.forEach { (name, model) -> fragmentBuilder.addIrClassModel(serialize(name, model)) } fragment.testFunInvocation?.let { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/FunctionalInterfacesUtils.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/FunctionalInterfacesUtils.kt index fa5a3a0d874..509aacb5ad4 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/FunctionalInterfacesUtils.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/FunctionalInterfacesUtils.kt @@ -5,8 +5,17 @@ package org.jetbrains.kotlin.backend.common.serialization +import org.jetbrains.kotlin.ir.util.IdSignature import java.util.regex.Pattern internal val functionPattern = Pattern.compile("^K?(Suspend)?Function\\d+$") internal val functionalPackages = listOf("kotlin", "kotlin.coroutines", "kotlin.reflect") + +fun checkIsFunctionInterface(idSig: IdSignature?): Boolean { + val publicSig = idSig?.asPublic() + return publicSig != null && + publicSig.packageFqName in functionalPackages && + publicSig.declarationFqName.isNotEmpty() && + functionPattern.matcher(publicSig.firstNameSegment).find() +} diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt index d0f2c86e366..3b4bd4930b9 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt @@ -124,14 +124,6 @@ class IrModuleDeserializerWithBuiltIns( symbol.signature to symbol }.toMap() - private fun checkIsFunctionInterface(idSig: IdSignature): Boolean { - val publicSig = idSig.asPublic() - return publicSig != null && - publicSig.packageFqName in functionalPackages && - publicSig.declarationFqName.isNotEmpty() && - functionPattern.matcher(publicSig.firstNameSegment).find() - } - override operator fun contains(idSig: IdSignature): Boolean { val topLevel = idSig.topLevelSignature() if (topLevel in irBuiltInsMap) return true diff --git a/js/js.serializer/src/js-ast.proto b/js/js.serializer/src/js-ast.proto index a5e3c70d0f1..ea204ab5bf0 100644 --- a/js/js.serializer/src/js-ast.proto +++ b/js/js.serializer/src/js-ast.proto @@ -419,6 +419,7 @@ message Fragment { optional int32 suite_function = 16; repeated int32 definitions = 17; optional CompositeBlock polyfills = 18; + repeated int32 optionalCrossModuleImports = 19; } message InlinedLocalDeclarations { @@ -514,4 +515,4 @@ message Chunk { message InlineData { repeated string inline_function_tags = 1; -} \ No newline at end of file +} diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java index 3833511343a..dde386f0742 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java @@ -33017,6 +33017,19 @@ public final class JsAstProtoBuf { * optional .org.jetbrains.kotlin.serialization.js.ast.CompositeBlock polyfills = 18; */ org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CompositeBlock getPolyfills(); + + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + java.util.List getOptionalCrossModuleImportsList(); + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + int getOptionalCrossModuleImportsCount(); + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + int getOptionalCrossModuleImports(int index); } /** * Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Fragment} @@ -33248,6 +33261,27 @@ public final class JsAstProtoBuf { bitField0_ |= 0x00000100; break; } + case 152: { + if (!((mutable_bitField0_ & 0x00040000) == 0x00040000)) { + optionalCrossModuleImports_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00040000; + } + optionalCrossModuleImports_.add(input.readInt32()); + break; + } + case 154: { + int length = input.readRawVarint32(); + int limit = input.pushLimit(length); + if (!((mutable_bitField0_ & 0x00040000) == 0x00040000) && input.getBytesUntilLimit() > 0) { + optionalCrossModuleImports_ = new java.util.ArrayList(); + mutable_bitField0_ |= 0x00040000; + } + while (input.getBytesUntilLimit() > 0) { + optionalCrossModuleImports_.add(input.readInt32()); + } + input.popLimit(limit); + break; + } } } } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) { @@ -33283,6 +33317,9 @@ public final class JsAstProtoBuf { if (((mutable_bitField0_ & 0x00010000) == 0x00010000)) { definitions_ = java.util.Collections.unmodifiableList(definitions_); } + if (((mutable_bitField0_ & 0x00040000) == 0x00040000)) { + optionalCrossModuleImports_ = java.util.Collections.unmodifiableList(optionalCrossModuleImports_); + } try { unknownFieldsCodedOutput.flush(); } catch (java.io.IOException e) { @@ -33800,6 +33837,28 @@ public final class JsAstProtoBuf { return polyfills_; } + public static final int OPTIONALCROSSMODULEIMPORTS_FIELD_NUMBER = 19; + private java.util.List optionalCrossModuleImports_; + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public java.util.List + getOptionalCrossModuleImportsList() { + return optionalCrossModuleImports_; + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public int getOptionalCrossModuleImportsCount() { + return optionalCrossModuleImports_.size(); + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public int getOptionalCrossModuleImports(int index) { + return optionalCrossModuleImports_.get(index); + } + private void initFields() { importedModule_ = java.util.Collections.emptyList(); importEntry_ = java.util.Collections.emptyList(); @@ -33819,6 +33878,7 @@ public final class JsAstProtoBuf { suiteFunction_ = 0; definitions_ = java.util.Collections.emptyList(); polyfills_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CompositeBlock.getDefaultInstance(); + optionalCrossModuleImports_ = java.util.Collections.emptyList(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -33971,6 +34031,9 @@ public final class JsAstProtoBuf { if (((bitField0_ & 0x00000100) == 0x00000100)) { output.writeMessage(18, polyfills_); } + for (int i = 0; i < optionalCrossModuleImports_.size(); i++) { + output.writeInt32(19, optionalCrossModuleImports_.get(i)); + } output.writeRawBytes(unknownFields); } @@ -34057,6 +34120,15 @@ public final class JsAstProtoBuf { size += org.jetbrains.kotlin.protobuf.CodedOutputStream .computeMessageSize(18, polyfills_); } + { + int dataSize = 0; + for (int i = 0; i < optionalCrossModuleImports_.size(); i++) { + dataSize += org.jetbrains.kotlin.protobuf.CodedOutputStream + .computeInt32SizeNoTag(optionalCrossModuleImports_.get(i)); + } + size += dataSize; + size += 2 * getOptionalCrossModuleImportsList().size(); + } size += unknownFields.size(); memoizedSerializedSize = size; return size; @@ -34187,6 +34259,8 @@ public final class JsAstProtoBuf { bitField0_ = (bitField0_ & ~0x00010000); polyfills_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CompositeBlock.getDefaultInstance(); bitField0_ = (bitField0_ & ~0x00020000); + optionalCrossModuleImports_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00040000); return this; } @@ -34291,6 +34365,11 @@ public final class JsAstProtoBuf { to_bitField0_ |= 0x00000100; } result.polyfills_ = polyfills_; + if (((bitField0_ & 0x00040000) == 0x00040000)) { + optionalCrossModuleImports_ = java.util.Collections.unmodifiableList(optionalCrossModuleImports_); + bitField0_ = (bitField0_ & ~0x00040000); + } + result.optionalCrossModuleImports_ = optionalCrossModuleImports_; result.bitField0_ = to_bitField0_; return result; } @@ -34418,6 +34497,16 @@ public final class JsAstProtoBuf { if (other.hasPolyfills()) { mergePolyfills(other.getPolyfills()); } + if (!other.optionalCrossModuleImports_.isEmpty()) { + if (optionalCrossModuleImports_.isEmpty()) { + optionalCrossModuleImports_ = other.optionalCrossModuleImports_; + bitField0_ = (bitField0_ & ~0x00040000); + } else { + ensureOptionalCrossModuleImportsIsMutable(); + optionalCrossModuleImports_.addAll(other.optionalCrossModuleImports_); + } + + } setUnknownFields( getUnknownFields().concat(other.unknownFields)); return this; @@ -36140,6 +36229,72 @@ public final class JsAstProtoBuf { return this; } + private java.util.List optionalCrossModuleImports_ = java.util.Collections.emptyList(); + private void ensureOptionalCrossModuleImportsIsMutable() { + if (!((bitField0_ & 0x00040000) == 0x00040000)) { + optionalCrossModuleImports_ = new java.util.ArrayList(optionalCrossModuleImports_); + bitField0_ |= 0x00040000; + } + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public java.util.List + getOptionalCrossModuleImportsList() { + return java.util.Collections.unmodifiableList(optionalCrossModuleImports_); + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public int getOptionalCrossModuleImportsCount() { + return optionalCrossModuleImports_.size(); + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public int getOptionalCrossModuleImports(int index) { + return optionalCrossModuleImports_.get(index); + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public Builder setOptionalCrossModuleImports( + int index, int value) { + ensureOptionalCrossModuleImportsIsMutable(); + optionalCrossModuleImports_.set(index, value); + + return this; + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public Builder addOptionalCrossModuleImports(int value) { + ensureOptionalCrossModuleImportsIsMutable(); + optionalCrossModuleImports_.add(value); + + return this; + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public Builder addAllOptionalCrossModuleImports( + java.lang.Iterable values) { + ensureOptionalCrossModuleImportsIsMutable(); + org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll( + values, optionalCrossModuleImports_); + + return this; + } + /** + * repeated int32 optionalCrossModuleImports = 19; + */ + public Builder clearOptionalCrossModuleImports() { + optionalCrossModuleImports_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00040000); + + return this; + } + // @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Fragment) }