diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 5749ee5d155..ff5f288d125 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -14317,6 +14317,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inline/anonymousObjects.kt"); } + @Test + @TestMetadata("approximateReturnedAnonymousObjects.kt") + public void testApproximateReturnedAnonymousObjects() throws Exception { + runTest("compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt"); + } + @Test @TestMetadata("assignment.kt") public void testAssignment() throws Exception { 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 4d5c0410f94..6647df6c551 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -1027,8 +1027,7 @@ public class DefaultErrorMessages { MAP.put(PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR, "Protected function call from public-API inline function is prohibited", NAME); MAP.put(INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE, "Invalid default value for inline parameter: ''{0}''. Only lambdas, anonymous functions, and callable references are supported", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES); MAP.put(NOT_SUPPORTED_INLINE_PARAMETER_IN_INLINE_PARAMETER_DEFAULT_VALUE, "Usage of inline parameter ''{0}'' in default value for another inline parameter is not supported", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES); - MAP.put(PRIVATE_INLINE_FUNCTIONS_RETURNING_ANONYMOUS_OBJECTS, "Return type of the private inline function can't be anonymous. It will be approximated to Any in 1.5." + - "See https://youtrack.jetbrains.com/issue/KT-33917 for more details"); + MAP.put(PRIVATE_INLINE_FUNCTIONS_RETURNING_ANONYMOUS_OBJECTS, "Return type of the private inline function can't be anonymous. It will be approximated to Any in a future release. See KT-33917 for more details"); //Inline non locals MAP.put(NON_LOCAL_RETURN_NOT_ALLOWED, "Can''t inline ''{0}'' here: it may contain non-local returns. Add ''crossinline'' modifier to parameter declaration ''{0}''", ELEMENT_TEXT); MAP.put(INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index ac2ed637f87..3e5126207e1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -1024,7 +1024,8 @@ public class DescriptorResolver { @NotNull KtDeclaration declaration, @NotNull KotlinType type, @NotNull BindingTrace trace, - @NotNull Iterable anonymousTypeTransformers + @NotNull Iterable anonymousTypeTransformers, + @NotNull LanguageVersionSettings languageVersionSettings ) { for (DeclarationSignatureAnonymousTypeTransformer transformer : anonymousTypeTransformers) { KotlinType transformedType = transformer.transformAnonymousType(descriptor, type); @@ -1038,7 +1039,12 @@ public class DescriptorResolver { return type; } - if (!DescriptorVisibilities.isPrivate(descriptor.getVisibility())) { + boolean isPrivate = DescriptorVisibilities.isPrivate(descriptor.getVisibility()); + boolean isInlineFunction = descriptor instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) descriptor).isInline(); + boolean isAnonymousReturnTypesInPrivateInlineFunctionsForbidden = + languageVersionSettings.supportsFeature(LanguageFeature.ApproximateAnonymousReturnTypesInPrivateInlineFunctions); + + if (!isPrivate || (isInlineFunction && isAnonymousReturnTypesInPrivateInlineFunctionsForbidden)) { if (type.getConstructor().getSupertypes().size() == 1) { return type.getConstructor().getSupertypes().iterator().next(); } @@ -1221,7 +1227,9 @@ public class DescriptorResolver { return wrappedTypeFactory.createRecursionIntolerantDeferredType(trace, () -> { PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings); KotlinType type = expressionTypingServices.getBodyExpressionType(trace, scope, dataFlowInfo, function, functionDescriptor); - KotlinType publicType = transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace, anonymousTypeTransformers); + KotlinType publicType = transformAnonymousTypeIfNeeded( + functionDescriptor, function, type, trace, anonymousTypeTransformers, languageVersionSettings + ); UnwrappedType approximatedType = typeApproximator.approximateDeclarationType(publicType, false, languageVersionSettings); KotlinType sanitizedType = declarationReturnTypeSanitizer.sanitizeReturnType(approximatedType, wrappedTypeFactory, trace, languageVersionSettings); functionsTypingVisitor.checkTypesForReturnStatements(function, trace, sanitizedType); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt index 7d715c66848..7ea99f687a2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/VariableTypeAndInitializerResolver.kt @@ -91,7 +91,9 @@ class VariableTypeAndInitializerResolver( val initializerType = resolveInitializerType( scopeForInitializer, variable.initializer!!, dataFlowInfo, inferenceSession, trace, local ) - transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace, anonymousTypeTransformers) + transformAnonymousTypeIfNeeded( + variableDescriptor, variable, initializerType, trace, anonymousTypeTransformers, languageVersionSettings + ) } else -> resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, inferenceSession, trace, local) @@ -157,7 +159,9 @@ class VariableTypeAndInitializerResolver( val delegatedType = getterReturnType?.let { approximateType(it, local) } ?: ErrorUtils.createErrorType("Type from delegate") - transformAnonymousTypeIfNeeded(variableDescriptor, property, delegatedType, trace, anonymousTypeTransformers) + transformAnonymousTypeIfNeeded( + variableDescriptor, property, delegatedType, trace, anonymousTypeTransformers, languageVersionSettings + ) } private fun resolveInitializerType( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt index 5fc1e415886..884007277f0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PrivateInlineFunctionsReturningAnonymousObjectsChecker.kt @@ -10,16 +10,15 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.psiUtil.isPrivate import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny object PrivateInlineFunctionsReturningAnonymousObjectsChecker : DeclarationChecker { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { - if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidAnonymousReturnTypesInPrivateInlineFunctions)) + if (context.languageVersionSettings.supportsFeature(LanguageFeature.ApproximateAnonymousReturnTypesInPrivateInlineFunctions)) return - if (descriptor !is SimpleFunctionDescriptor || !descriptor.isInline || !declaration.isPrivate() || declaration !is KtNamedFunction) + if (descriptor !is SimpleFunctionDescriptor || !descriptor.isInline || !DescriptorVisibilities.isPrivate(descriptor.visibility) || declaration !is KtNamedFunction) return val returnTypeConstructor = descriptor.returnType?.constructor ?: return diff --git a/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.fir.kt b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.fir.kt new file mode 100644 index 00000000000..e5a992792f2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.fir.kt @@ -0,0 +1,52 @@ +// !LANGUAGE: +ApproximateAnonymousReturnTypesInPrivateInlineFunctions + +private inline fun foo1(crossinline f: () -> Int) = object { + fun bar(): Int = f() +} + +interface I1 +interface I2 + +private inline fun foo2(crossinline f: () -> Int) = object : I1 { + fun bar(): Int = f() +} + +private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { + fun bar(): Int = f() +} + +private fun foo4(f: () -> Int) = object { + fun bar(): Int = f() +} + +fun test1(b: Boolean) { + var x = ")!>foo1 { 1 } + if (b) { + x = ")!>foo1 { 2 } + } + x.bar() +} + +fun test2(b: Boolean) { + var x = foo2 { 1 } + if (b) { + x = foo2 { 2 } + } + x.bar() +} + +fun test3(b: Boolean) { + var x = | { super() } public final fun bar(): R|kotlin/Int| { ^bar R|/f|.R|SubstitutionOverride|() }}")!>foo3 { 1 } + if (b) { + x = | { super() } public final fun bar(): R|kotlin/Int| { ^bar R|/f|.R|SubstitutionOverride|() }}")!>foo3 { 2 } + } + x.bar() +} + +fun test4(b: Boolean) { + var x = ")!>foo4 { 1 } + if (b) { + x = ")!>foo4 { 2 } + } + x.bar() +} diff --git a/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt new file mode 100644 index 00000000000..7c57464c732 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt @@ -0,0 +1,52 @@ +// !LANGUAGE: +ApproximateAnonymousReturnTypesInPrivateInlineFunctions + +private inline fun foo1(crossinline f: () -> Int) = object { + fun bar(): Int = f() +} + +interface I1 +interface I2 + +private inline fun foo2(crossinline f: () -> Int) = object : I1 { + fun bar(): Int = f() +} + +private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { + fun bar(): Int = f() +} + +private fun foo4(f: () -> Int) = object { + fun bar(): Int = f() +} + +fun test1(b: Boolean) { + var x = foo1 { 1 } + if (b) { + x = foo1 { 2 } + } + x.bar() +} + +fun test2(b: Boolean) { + var x = foo2 { 1 } + if (b) { + x = foo2 { 2 } + } + x.bar() +} + +fun test3(b: Boolean) { + var x = ")!>foo3 { 1 } + if (b) { + x = ")!>foo3 { 2 } + } + x.bar() +} + +fun test4(b: Boolean) { + var x = ")!>foo4 { 1 } + if (b) { + x = ")!>foo4 { 2 } + } + x.bar() +} diff --git a/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.txt b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.txt new file mode 100644 index 00000000000..29a27873fcb --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.txt @@ -0,0 +1,22 @@ +package + +private inline fun foo1(/*0*/ crossinline f: () -> kotlin.Int): kotlin.Any +private inline fun foo2(/*0*/ crossinline f: () -> kotlin.Int): I1 +private inline fun foo3(/*0*/ crossinline f: () -> kotlin.Int): foo3. +private fun foo4(/*0*/ f: () -> kotlin.Int): foo4. +public fun test1(/*0*/ b: kotlin.Boolean): kotlin.Unit +public fun test2(/*0*/ b: kotlin.Boolean): kotlin.Unit +public fun test3(/*0*/ b: kotlin.Boolean): kotlin.Unit +public fun test4(/*0*/ b: kotlin.Boolean): kotlin.Unit + +public interface I1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface I2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.fir.kt b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.fir.kt index b7f01aac27d..7e3dfc4bb9a 100644 --- a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.fir.kt +++ b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.fir.kt @@ -1,11 +1,52 @@ -private inline fun foo(crossinline f: () -> Int) = object { +// !LANGUAGE: -ApproximateAnonymousReturnTypesInPrivateInlineFunctions + +private inline fun foo1(crossinline f: () -> Int) = object { fun bar(): Int = f() } -fun test(b: Boolean) { - var x = foo { 1 } +interface I1 +interface I2 + +private inline fun foo2(crossinline f: () -> Int) = object : I1 { + fun bar(): Int = f() +} + +private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { + fun bar(): Int = f() +} + +private fun foo4(f: () -> Int) = object { + fun bar(): Int = f() +} + +fun test1(b: Boolean) { + var x = ")!>foo1 { 1 } if (b) { - x = foo { 2 } + x = ")!>foo1 { 2 } } x.bar() -} \ No newline at end of file +} + +fun test2(b: Boolean) { + var x = foo2 { 1 } + if (b) { + x = foo2 { 2 } + } + x.bar() +} + +fun test3(b: Boolean) { + var x = | { super() } public final fun bar(): R|kotlin/Int| { ^bar R|/f|.R|SubstitutionOverride|() }}")!>foo3 { 1 } + if (b) { + x = | { super() } public final fun bar(): R|kotlin/Int| { ^bar R|/f|.R|SubstitutionOverride|() }}")!>foo3 { 2 } + } + x.bar() +} + +fun test4(b: Boolean) { + var x = ")!>foo4 { 1 } + if (b) { + x = ")!>foo4 { 2 } + } + x.bar() +} diff --git a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt index 8a5b43e9f76..a82a5f52719 100644 --- a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt +++ b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.kt @@ -1,11 +1,52 @@ -private inline fun foo(crossinline f: () -> Int) = object { +// !LANGUAGE: -ApproximateAnonymousReturnTypesInPrivateInlineFunctions + +private inline fun foo1(crossinline f: () -> Int) = object { fun bar(): Int = f() } -fun test(b: Boolean) { - var x = foo { 1 } +interface I1 +interface I2 + +private inline fun foo2(crossinline f: () -> Int) = object : I1 { + fun bar(): Int = f() +} + +private inline fun foo3(crossinline f: () -> Int) = object : I1, I2 { + fun bar(): Int = f() +} + +private fun foo4(f: () -> Int) = object { + fun bar(): Int = f() +} + +fun test1(b: Boolean) { + var x = ")!>foo1 { 1 } if (b) { - x = foo { 2 } + x = ")!>foo1 { 2 } } x.bar() -} \ No newline at end of file +} + +fun test2(b: Boolean) { + var x = ")!>foo2 { 1 } + if (b) { + x = ")!>foo2 { 2 } + } + x.bar() +} + +fun test3(b: Boolean) { + var x = ")!>foo3 { 1 } + if (b) { + x = ")!>foo3 { 2 } + } + x.bar() +} + +fun test4(b: Boolean) { + var x = ")!>foo4 { 1 } + if (b) { + x = ")!>foo4 { 2 } + } + x.bar() +} diff --git a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.txt b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.txt index df3a53f2a39..d16f56e2003 100644 --- a/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.txt +++ b/compiler/testData/diagnostics/tests/inline/returnedAnonymousObjects.txt @@ -1,4 +1,22 @@ package -private inline fun foo(/*0*/ crossinline f: () -> kotlin.Int): foo. -public fun test(/*0*/ b: kotlin.Boolean): kotlin.Unit +private inline fun foo1(/*0*/ crossinline f: () -> kotlin.Int): foo1. +private inline fun foo2(/*0*/ crossinline f: () -> kotlin.Int): foo2. +private inline fun foo3(/*0*/ crossinline f: () -> kotlin.Int): foo3. +private fun foo4(/*0*/ f: () -> kotlin.Int): foo4. +public fun test1(/*0*/ b: kotlin.Boolean): kotlin.Unit +public fun test2(/*0*/ b: kotlin.Boolean): kotlin.Unit +public fun test3(/*0*/ b: kotlin.Boolean): kotlin.Unit +public fun test4(/*0*/ b: kotlin.Boolean): kotlin.Unit + +public interface I1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface I2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index f5f0983cb1b..378bdfa2eff 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -14323,6 +14323,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inline/anonymousObjects.kt"); } + @Test + @TestMetadata("approximateReturnedAnonymousObjects.kt") + public void testApproximateReturnedAnonymousObjects() throws Exception { + runTest("compiler/testData/diagnostics/tests/inline/approximateReturnedAnonymousObjects.kt"); + } + @Test @TestMetadata("assignment.kt") public void testAssignment() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b7aaedc80d1..f0760698a5d 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -18723,11 +18723,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class MixedNamedPosition extends AbstractLightAnalysisModeTest { - @TestMetadata("varargsEvaluationOrder.kt") - public void ignoreVarargsEvaluationOrder() throws Exception { - runTest("compiler/testData/codegen/box/mixedNamedPosition/varargsEvaluationOrder.kt"); - } - private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -18750,6 +18745,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testVarargs() throws Exception { runTest("compiler/testData/codegen/box/mixedNamedPosition/varargs.kt"); } + + @TestMetadata("varargsEvaluationOrder.kt") + public void testVarargsEvaluationOrder() throws Exception { + runTest("compiler/testData/codegen/box/mixedNamedPosition/varargsEvaluationOrder.kt"); + } } @TestMetadata("compiler/testData/codegen/box/multiDecl") diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 47c8028d712..1fd27a05cc3 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -137,7 +137,7 @@ enum class LanguageFeature( AdaptedCallableReferenceAgainstReflectiveType(KOTLIN_1_5, defaultState = LanguageFeature.State.DISABLED), InferenceCompatibility(KOTLIN_1_5, kind = BUG_FIX), RequiredPrimaryConstructorDelegationCallInEnums(KOTLIN_1_5, kind = BUG_FIX), - ForbidAnonymousReturnTypesInPrivateInlineFunctions(KOTLIN_1_5, kind = BUG_FIX), + ApproximateAnonymousReturnTypesInPrivateInlineFunctions(KOTLIN_1_5, kind = BUG_FIX), ForbidReferencingToUnderscoreNamedParameterOfCatchBlock(KOTLIN_1_5, kind = BUG_FIX), UseCorrectExecutionOrderForVarargArguments(KOTLIN_1_5, kind = BUG_FIX), JvmRecordSupport(KOTLIN_1_5),