diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 64188971829..2124fb27f51 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -15340,6 +15340,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT } } + @Nested + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + public class DifferentDependencyVersion { + @Test + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("kt51194_java.kt") + public void testKt51194_java() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_java.kt"); + } + + @Test + @TestMetadata("kt51194_javaAndKotlin.kt") + public void testKt51194_javaAndKotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_javaAndKotlin.kt"); + } + + @Test + @TestMetadata("kt51194_kotlin.kt") + public void testKt51194_kotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_kotlin.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 72b80bc2ff9..f7e573d2be4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -597,6 +597,8 @@ public interface Errors { DiagnosticFactory2> CONFLICTING_INHERITED_MEMBERS = DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2> CONFLICTING_INHERITED_MEMBERS_WARNING = + DiagnosticFactory2.create(WARNING, DECLARATION_NAME); DiagnosticFactory2 ABSTRACT_MEMBER_NOT_IMPLEMENTED = DiagnosticFactory2.create(ERROR, DECLARATION_NAME); DiagnosticFactory2 ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED = diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 294456d3c86..03b555bdae5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -887,6 +887,7 @@ public class DefaultErrorMessages { FQ_NAMES_IN_TYPES); MAP.put(CONFLICTING_INHERITED_MEMBERS, "{0} inherits conflicting members: {1}", NAME, CommonRenderers.commaSeparated(FQ_NAMES_IN_TYPES)); + MAP.put(CONFLICTING_INHERITED_MEMBERS_WARNING, "{0} inherits conflicting members: {1}; This warning will became error in future releases. See https://youtrack.jetbrains.com/issue/KT-51194", NAME, CommonRenderers.commaSeparated(FQ_NAMES_IN_TYPES)); MAP.put(ABSTRACT_MEMBER_NOT_IMPLEMENTED, "{0} is not abstract and does not implement abstract member {1}", RENDER_CLASS_OR_OBJECT, FQ_NAMES_IN_TYPES); MAP.put(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED, "{0} is not abstract and does not implement abstract base class member {1}", diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt index b658bea378b..e9aaae9ea83 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.reportOnDeclarationAs @@ -254,6 +255,23 @@ open class LazyClassMemberScope( } } }) + for (descriptor in result) { + if (descriptor !is FunctionDescriptorImpl) continue + for (overriddenFunction in descriptor.overriddenDescriptors) { + if (overriddenFunction !is FunctionDescriptorImpl) continue + val conflictedDescriptor = overriddenFunction.getUserData(DeserializedDeclarationsFromSupertypeConflictDataKey) ?: continue + reportOnDeclarationAs( + trace, + thisDescriptor + ) { ktClassOrObject -> + Errors.CONFLICTING_INHERITED_MEMBERS_WARNING.on( + ktClassOrObject, + thisDescriptor, + listOf(overriddenFunction, conflictedDescriptor) + ) + } + } + } OverrideResolver.resolveUnknownVisibilities(result, trace) } diff --git a/compiler/testData/codegen/box/differentDependencyVersion/kt51194_java.kt b/compiler/testData/codegen/box/differentDependencyVersion/kt51194_java.kt new file mode 100644 index 00000000000..97354630450 --- /dev/null +++ b/compiler/testData/codegen/box/differentDependencyVersion/kt51194_java.kt @@ -0,0 +1,29 @@ +// TARGET_BACKEND: JVM +// ISSUE: KT-51194 + +// MODULE: coreLib_1 +// FILE: Base.java +public interface Base { + Object foo(); +} + +// MODULE: lib(coreLib_1) +// FILE: Derived.java +public abstract class Derived implements Base { + @Override + public Object foo() { + return null; + } +} + +// MODULE: coreLib_2 +// FILE: Base.java +public interface Base { + T foo(); +} + +// MODULE: main(coreLib_2, lib) +// FILE: main.kt +class Implementation : Derived() + +fun box() = "OK" diff --git a/compiler/testData/codegen/box/differentDependencyVersion/kt51194_javaAndKotlin.kt b/compiler/testData/codegen/box/differentDependencyVersion/kt51194_javaAndKotlin.kt new file mode 100644 index 00000000000..63b203fbdb7 --- /dev/null +++ b/compiler/testData/codegen/box/differentDependencyVersion/kt51194_javaAndKotlin.kt @@ -0,0 +1,30 @@ +// TARGET_BACKEND: JVM +// ISSUE: KT-51194 +// DIAGNOSTICS: +CONFLICTING_INHERITED_MEMBERS_WARNING +// IGNORE_BACKEND_FIR: JVM_IR +// FIR status: FIR correctly reports CONFLICTING_INHERITED_MEMBERS, so this test should not pass design +// For details see related issue + +// MODULE: coreLib_1 +// FILE: Base.java +public interface Base { + Object foo(); +} + +// MODULE: lib(coreLib_1) +// FILE: Derived.kt +abstract class Derived : Base { + override fun foo(): Any? = null +} + +// MODULE: coreLib_2 +// FILE: Base.java +public interface Base { + T foo(); +} + +// MODULE: main(coreLib_2, lib) +// FILE: main.kt +class Implementation : Derived() + +fun box() = "OK" diff --git a/compiler/testData/codegen/box/differentDependencyVersion/kt51194_kotlin.kt b/compiler/testData/codegen/box/differentDependencyVersion/kt51194_kotlin.kt new file mode 100644 index 00000000000..c13d82a02dc --- /dev/null +++ b/compiler/testData/codegen/box/differentDependencyVersion/kt51194_kotlin.kt @@ -0,0 +1,30 @@ +// TARGET_BACKEND: JVM +// ISSUE: KT-51194 +// DIAGNOSTICS: +CONFLICTING_INHERITED_MEMBERS_WARNING +// IGNORE_BACKEND_FIR: JVM_IR +// FIR status: FIR correctly reports CONFLICTING_INHERITED_MEMBERS, so this test should not pass design +// For details see related issue + +// MODULE: coreLib_1 +// FILE: Base.kt +interface Base { + fun foo(): Any? +} + +// MODULE: lib(coreLib_1) +// FILE: Derived.kt +abstract class Derived : Base { + override fun foo(): Any? = null +} + +// MODULE: coreLib_2 +// FILE: Base.kt +interface Base { + fun foo(): T +} + +// MODULE: main(coreLib_2, lib) +// FILE: main.kt +class Implementation : Derived() + +fun box() = "OK" diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index ef1d7063c9f..c44290014d7 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -15220,6 +15220,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + public class DifferentDependencyVersion { + @Test + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @Test + @TestMetadata("kt51194_java.kt") + public void testKt51194_java() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_java.kt"); + } + + @Test + @TestMetadata("kt51194_javaAndKotlin.kt") + public void testKt51194_javaAndKotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_javaAndKotlin.kt"); + } + + @Test + @TestMetadata("kt51194_kotlin.kt") + public void testKt51194_kotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_kotlin.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 9c8442f6b80..e6b94cc02c4 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -15340,6 +15340,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @Nested + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + public class DifferentDependencyVersion { + @Test + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("kt51194_java.kt") + public void testKt51194_java() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_java.kt"); + } + + @Test + @TestMetadata("kt51194_javaAndKotlin.kt") + public void testKt51194_javaAndKotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_javaAndKotlin.kt"); + } + + @Test + @TestMetadata("kt51194_kotlin.kt") + public void testKt51194_kotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_kotlin.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index cb0c0468d06..44449885e9c 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12495,6 +12495,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DifferentDependencyVersion extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("kt51194_java.kt") + public void testKt51194_java() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_java.kt"); + } + + @TestMetadata("kt51194_javaAndKotlin.kt") + public void testKt51194_javaAndKotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_javaAndKotlin.kt"); + } + + @TestMetadata("kt51194_kotlin.kt") + public void testKt51194_kotlin() throws Exception { + runTest("compiler/testData/codegen/box/differentDependencyVersion/kt51194_kotlin.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/descriptorUtil.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/descriptorUtil.kt index 83b034835fe..5d23b8e35f4 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/descriptorUtil.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/descriptorUtil.kt @@ -86,3 +86,5 @@ fun DeclarationDescriptor.containingPackage(): FqName? { require(container is PackageFragmentDescriptor?) return container?.fqName } + +object DeserializedDeclarationsFromSupertypeConflictDataKey : CallableDescriptor.UserDataKey diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt index f1f3756ef1f..061e02e1e27 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.AbstractClassDescriptor import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor +import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation @@ -327,7 +328,9 @@ class DeserializedClassDescriptor( fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor ) { - // TODO report conflicts + if (fromCurrent is FunctionDescriptorImpl) { + fromCurrent.putInUserDataMap(DeserializedDeclarationsFromSupertypeConflictDataKey, fromSuper) + } } }) } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index 20e77f75015..20eb332b3b5 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -11766,6 +11766,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + public class DifferentDependencyVersion { + @Test + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index c869d56bc2e..453a8ce77e3 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -11808,6 +11808,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + public class DifferentDependencyVersion { + @Test + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT") diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 2efd74d17d5..23f6c989232 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -9767,6 +9767,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest } } + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DifferentDependencyVersion extends AbstractIrCodegenBoxWasmTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath); + } + + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + } + @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/ExternalTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/ExternalTestGenerated.java index 24b10f49458..baaf758b1e6 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/ExternalTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/ExternalTestGenerated.java @@ -12740,6 +12740,18 @@ public class ExternalTestGenerated extends AbstractExternalNativeBlackBoxTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/differentDependencyVersion") + @TestDataPath("$PROJECT_ROOT") + @Tag("external") + @UseExtTestCaseGroupProvider() + public class DifferentDependencyVersion { + @Test + public void testAllFilesPresentInDifferentDependencyVersion() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/differentDependencyVersion"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/directInvokeOptimization") @TestDataPath("$PROJECT_ROOT")