KT-11111:

- override by a final inline fun is a warning
- override by a fun with reified type parameters is an error
This commit is contained in:
Dmitry Petrov
2016-04-19 11:58:04 +03:00
parent ef0f512201
commit 420c7a0285
8 changed files with 109 additions and 13 deletions
@@ -786,7 +786,9 @@ public interface Errors {
DiagnosticFactory2<KtElement, KtExpression, DeclarationDescriptor> USAGE_IS_NOT_INLINABLE = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<KtElement, KtElement, DeclarationDescriptor> NULLABLE_INLINE_PARAMETER = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<KtElement, KtElement, DeclarationDescriptor> RECURSION_IN_INLINE = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<KtElement> DECLARATION_CANT_BE_INLINED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtDeclaration> DECLARATION_CANT_BE_INLINED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtDeclaration> OVERRIDE_BY_INLINE = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
DiagnosticFactory0<PsiElement> REIFIED_TYPE_PARAMETER_IN_OVERRIDE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, CallableDescriptor> INLINE_CALL_CYCLE = DiagnosticFactory1.create(ERROR, DEFAULT);
DiagnosticFactory0<PsiElement> NON_LOCAL_RETURN_IN_DISABLED_INLINE = DiagnosticFactory0.create(ERROR);
@@ -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);
@@ -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
}
@@ -13,11 +13,11 @@ abstract class A {
inline final fun good4() {}
<!DECLARATION_CANT_BE_INLINED!>inline open protected fun wrong1() {}<!>
<!DECLARATION_CANT_BE_INLINED!>inline open protected fun wrong1()<!> {}
<!DECLARATION_CANT_BE_INLINED!>inline open public fun wrong2() {}<!>
<!DECLARATION_CANT_BE_INLINED!>inline open public fun wrong2()<!> {}
<!DECLARATION_CANT_BE_INLINED!>inline open fun wrong3() {}<!>
<!DECLARATION_CANT_BE_INLINED!>inline open fun wrong3()<!> {}
<!DECLARATION_CANT_BE_INLINED!>inline abstract protected fun wrong4()<!>
@@ -31,13 +31,13 @@ interface B {
inline private fun good1() {}
<!DECLARATION_CANT_BE_INLINED!>inline fun wrong1() {}<!>
<!DECLARATION_CANT_BE_INLINED!>inline fun wrong1()<!> {}
<!DECLARATION_CANT_BE_INLINED!>inline open fun wrong2() {}<!>
<!DECLARATION_CANT_BE_INLINED!>inline open fun wrong2()<!> {}
<!DECLARATION_CANT_BE_INLINED!>inline open public fun wrong3() {}<!>
<!DECLARATION_CANT_BE_INLINED!>inline open public fun wrong3()<!> {}
<!DECLARATION_CANT_BE_INLINED!>inline open fun wrong4() {}<!>
<!DECLARATION_CANT_BE_INLINED!>inline open fun wrong4()<!> {}
<!DECLARATION_CANT_BE_INLINED!>inline fun wrong5()<!>
@@ -0,0 +1,34 @@
// !DIAGNOSTICS: -NOTHING_TO_INLINE -UNUSED_PARAMETER
interface IBase {
fun foo()
fun bar()
fun <T> qux(x: T)
}
class CDerived : IBase {
<!OVERRIDE_BY_INLINE!>override inline final fun foo()<!> {}
<!DECLARATION_CANT_BE_INLINED!>override inline fun bar()<!> {}
<!OVERRIDE_BY_INLINE!>override inline final fun <<!REIFIED_TYPE_PARAMETER_IN_OVERRIDE!>reified<!> T> qux(x: T)<!> {}
class CNested : IBase {
<!OVERRIDE_BY_INLINE!>override inline final fun foo()<!> {}
<!DECLARATION_CANT_BE_INLINED!>override inline fun bar()<!> {}
<!OVERRIDE_BY_INLINE!>override inline final fun <<!REIFIED_TYPE_PARAMETER_IN_OVERRIDE!>reified<!> T> qux(x: T)<!> {}
}
val anObject = object : IBase {
<!OVERRIDE_BY_INLINE!>override inline final fun foo()<!> {}
<!DECLARATION_CANT_BE_INLINED!>override inline fun bar()<!> {}
<!OVERRIDE_BY_INLINE!>override inline final fun <<!REIFIED_TYPE_PARAMETER_IN_OVERRIDE!>reified<!> T> qux(x: T)<!> {}
}
fun aMethod() {
class CLocal : IBase {
<!OVERRIDE_BY_INLINE!>override inline final fun foo()<!> {}
<!DECLARATION_CANT_BE_INLINED!>override inline fun bar()<!> {}
<!OVERRIDE_BY_INLINE!>override inline final fun <<!REIFIED_TYPE_PARAMETER_IN_OVERRIDE!>reified<!> T> qux(x: T)<!> {}
}
}
}
@@ -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 </*0*/ reified T> 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 </*0*/ reified T> 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 </*0*/ T> qux(/*0*/ x: T): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -26,7 +26,7 @@ open class Base {
}
class Derived: Base() {
inline final override fun foo(<!NOT_YET_SUPPORTED_IN_INLINE!>a: Int<!>) {
<!OVERRIDE_BY_INLINE!>inline final override fun foo(<!NOT_YET_SUPPORTED_IN_INLINE!>a: Int<!>)<!> {
}
}
@@ -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");