diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 7a52aceb929..67a204f9c33 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -786,7 +786,9 @@ public interface Errors { DiagnosticFactory2 USAGE_IS_NOT_INLINABLE = DiagnosticFactory2.create(ERROR); DiagnosticFactory2 NULLABLE_INLINE_PARAMETER = DiagnosticFactory2.create(ERROR); DiagnosticFactory2 RECURSION_IN_INLINE = DiagnosticFactory2.create(ERROR); - DiagnosticFactory0 DECLARATION_CANT_BE_INLINED = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 DECLARATION_CANT_BE_INLINED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE); + DiagnosticFactory0 OVERRIDE_BY_INLINE = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE); + DiagnosticFactory0 REIFIED_TYPE_PARAMETER_IN_OVERRIDE = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 INLINE_CALL_CYCLE = DiagnosticFactory1.create(ERROR, DEFAULT); DiagnosticFactory0 NON_LOCAL_RETURN_IN_DISABLED_INLINE = DiagnosticFactory0.create(ERROR); 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 0416115e680..f769c629113 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -729,6 +729,8 @@ public class DefaultErrorMessages { MAP.put(PRIVATE_CLASS_MEMBER_FROM_INLINE, "Non-private inline function cannot access members of private classes: ''{0}''", SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); MAP.put(NOT_YET_SUPPORTED_IN_INLINE, "''{0}'' construction is not yet supported in inline functions", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES); MAP.put(DECLARATION_CANT_BE_INLINED, "'inline' modifier is not allowed on virtual members. Only private or final members can be inlined"); + MAP.put(OVERRIDE_BY_INLINE, "Override by an inline function"); + MAP.put(REIFIED_TYPE_PARAMETER_IN_OVERRIDE, "Override by a function with reified type parameter"); MAP.put(NOTHING_TO_INLINE, "Expected performance impact of inlining ''{0}'' can be insignificant. Inlining works best for functions with lambda parameters", SHORT_NAMES_IN_TYPES); MAP.put(USAGE_IS_NOT_INLINABLE, "Illegal usage of inline-parameter ''{0}'' in ''{1}''. Add ''noinline'' modifier to the parameter declaration", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES); MAP.put(NULLABLE_INLINE_PARAMETER, "Inline-parameter ''{0}'' of ''{1}'' must not be nullable. Add ''noinline'' modifier to the parameter declaration or make its type not nullable", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineAnalyzerExtension.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineAnalyzerExtension.kt index 685dc9fd83b..227da5008b0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineAnalyzerExtension.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/inline/InlineAnalyzerExtension.kt @@ -31,7 +31,7 @@ object InlineAnalyzerExtension : FunctionAnalyzerExtension.AnalyzerExtension { assert(InlineUtil.isInline(descriptor)) { "This method should be invoked on inline function: " + descriptor } checkDefaults(descriptor, function, trace) - checkNotVirtual(descriptor, function, trace) + checkModalityAndOverrides(descriptor, function, trace) checkHasInlinableAndNullability(descriptor, function, trace) val visitor = object : KtVisitorVoid() { @@ -73,15 +73,35 @@ object InlineAnalyzerExtension : FunctionAnalyzerExtension.AnalyzerExtension { } } - private fun checkNotVirtual( + private fun checkModalityAndOverrides( functionDescriptor: FunctionDescriptor, function: KtFunction, trace: BindingTrace) { - if (Visibilities.isPrivate(functionDescriptor.visibility) || functionDescriptor.modality === Modality.FINAL) { + if (functionDescriptor.containingDeclaration is PackageFragmentDescriptor) { return } - if (functionDescriptor.containingDeclaration is PackageFragmentDescriptor) { + if (Visibilities.isPrivate(functionDescriptor.visibility)) { + return + } + + val overridesAnything = functionDescriptor.overriddenDescriptors.isNotEmpty() + + if (overridesAnything) { + val ktTypeParameters = function.typeParameters + for (typeParameter in functionDescriptor.typeParameters) { + if (typeParameter.isReified) { + val ktTypeParameter = ktTypeParameters[typeParameter.index] + val reportOn = ktTypeParameter.modifierList?.getModifier(KtTokens.REIFIED_KEYWORD) ?: ktTypeParameter + trace.report(Errors.REIFIED_TYPE_PARAMETER_IN_OVERRIDE.on(reportOn)) + } + } + } + + if (functionDescriptor.modality == Modality.FINAL) { + if (overridesAnything) { + trace.report(Errors.OVERRIDE_BY_INLINE.on(function)) + } return } diff --git a/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt b/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt index eeff471002c..bcc84bf8ac2 100644 --- a/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt +++ b/compiler/testData/diagnostics/tests/inline/nonVirtualMembersWithInline.kt @@ -13,11 +13,11 @@ abstract class A { inline final fun good4() {} - inline open protected fun wrong1() {} + inline open protected fun wrong1() {} - inline open public fun wrong2() {} + inline open public fun wrong2() {} - inline open fun wrong3() {} + inline open fun wrong3() {} inline abstract protected fun wrong4() @@ -31,13 +31,13 @@ interface B { inline private fun good1() {} - inline fun wrong1() {} + inline fun wrong1() {} - inline open fun wrong2() {} + inline open fun wrong2() {} - inline open public fun wrong3() {} + inline open public fun wrong3() {} - inline open fun wrong4() {} + inline open fun wrong4() {} inline fun wrong5() diff --git a/compiler/testData/diagnostics/tests/inline/overrideWithInline.kt b/compiler/testData/diagnostics/tests/inline/overrideWithInline.kt new file mode 100644 index 00000000000..727e9145c4a --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/overrideWithInline.kt @@ -0,0 +1,34 @@ +// !DIAGNOSTICS: -NOTHING_TO_INLINE -UNUSED_PARAMETER + +interface IBase { + fun foo() + fun bar() + fun qux(x: T) +} + +class CDerived : IBase { + override inline final fun foo() {} + override inline fun bar() {} + override inline final fun <reified T> qux(x: T) {} + + class CNested : IBase { + override inline final fun foo() {} + override inline fun bar() {} + override inline final fun <reified T> qux(x: T) {} + } + + val anObject = object : IBase { + override inline final fun foo() {} + override inline fun bar() {} + override inline final fun <reified T> qux(x: T) {} + } + + fun aMethod() { + class CLocal : IBase { + override inline final fun foo() {} + override inline fun bar() {} + override inline final fun <reified T> qux(x: T) {} + } + } +} + diff --git a/compiler/testData/diagnostics/tests/inline/overrideWithInline.txt b/compiler/testData/diagnostics/tests/inline/overrideWithInline.txt new file mode 100644 index 00000000000..368f6e28dbd --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/overrideWithInline.txt @@ -0,0 +1,32 @@ +package + +public final class CDerived : IBase { + public constructor CDerived() + public final val anObject: IBase + public final fun aMethod(): kotlin.Unit + public open inline override /*1*/ fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final inline override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline override /*1*/ fun qux(/*0*/ x: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class CNested : IBase { + public constructor CNested() + public open inline override /*1*/ fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final inline override /*1*/ fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline override /*1*/ fun qux(/*0*/ x: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public interface IBase { + public abstract fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun qux(/*0*/ x: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt b/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt index 30be1897f4d..2c6a2d2c436 100644 --- a/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt +++ b/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt @@ -26,7 +26,7 @@ open class Base { } class Derived: Base() { - inline final override fun foo(a: Int) { + inline final override fun foo(a: Int) { } } \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index b2e644f977e..4438f8570f9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -9417,6 +9417,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("overrideWithInline.kt") + public void testOverrideWithInline() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inline/overrideWithInline.kt"); + doTest(fileName); + } + @TestMetadata("parenthesized.kt") public void testParenthesized() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inline/parenthesized.kt");