Skip to content

Commit

Permalink
Value classes: Report lacking @JvmInline only on JVM backend
Browse files Browse the repository at this point in the history
Report when @JvmInline is applied on non-value class.
  • Loading branch information
ilmirus committed Nov 27, 2020
1 parent 92f1681 commit ca3e7cf
Show file tree
Hide file tree
Showing 27 changed files with 215 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForParameterTypes
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jetbrains.kotlin.resolve.jvm.checkers

import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.JVM_INLINE_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm

class JvmInlineApplicabilityChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (descriptor !is ClassDescriptor) return
val annotation = descriptor.annotations.findAnnotation(JVM_INLINE_ANNOTATION_FQ_NAME)
if (annotation != null && !descriptor.isValue) {
val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return
context.trace.report(ErrorsJvm.JVM_INLINE_WITHOUT_VALUE_CLASS.on(annotationEntry))
}

if (descriptor.isValue && annotation == null) {
val valueKeyword = declaration.modifierList?.getModifier(KtTokens.VALUE_KEYWORD) ?: return
context.trace.report(ErrorsJvm.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION.on(valueKeyword))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES, TO_STRING);

MAP.put(DANGEROUS_CHARACTERS, "Name contains characters which can cause problems on Windows: {0}", STRING);

MAP.put(VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, "Value classes without @JvmInline annotation are not supported yet");
MAP.put(JVM_INLINE_WITHOUT_VALUE_CLASS, "@JvmInline annotation is only applicable to value classes");
}

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ public interface ErrorsJvm {

DiagnosticFactory1<PsiElement, String> DANGEROUS_CHARACTERS = DiagnosticFactory1.create(WARNING);

DiagnosticFactory0<PsiElement> VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> JVM_INLINE_WITHOUT_VALUE_CLASS = DiagnosticFactory0.create(ERROR);

@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
JvmFieldApplicabilityChecker(),
TypeParameterBoundIsNotArrayChecker(),
JvmSyntheticApplicabilityChecker(),
JvmInlineApplicabilityChecker(),
StrictfpApplicabilityChecker(),
JvmAnnotationsTargetNonExistentAccessorChecker(),
BadInheritedJavaSignaturesChecker,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,6 @@ public interface Errors {
DiagnosticFactory0<KtTypeReference> INLINE_CLASS_CANNOT_BE_RECURSIVE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> RESERVED_MEMBER_INSIDE_INLINE_CLASS = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION = DiagnosticFactory0.create(ERROR);

// Result class

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,6 @@ public static DiagnosticRenderer getRendererForDiagnostic(@NotNull UnboundDiagno
MAP.put(INLINE_CLASS_CANNOT_BE_RECURSIVE, "Inline class cannot be recursive");
MAP.put(RESERVED_MEMBER_INSIDE_INLINE_CLASS, "Member with the name ''{0}'' is reserved for future releases", STRING);
MAP.put(SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_INLINE_CLASS, "Secondary constructors with bodies are reserved for for future releases");
MAP.put(VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, "Value classes without @JvmInline annotation are not supported yet");

MAP.put(RESULT_CLASS_IN_RETURN_TYPE, "'kotlin.Result' cannot be used as a return type");
MAP.put(RESULT_CLASS_WITH_NULLABLE_OPERATOR, "Expression of type 'kotlin.Result' cannot be used as a left operand of ''{0}''", STRING);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.modalityModifier
import org.jetbrains.kotlin.resolve.*
Expand Down Expand Up @@ -88,10 +87,6 @@ object InlineClassDeclarationChecker : DeclarationChecker {
}
}
}

if (descriptor.isValue && !descriptor.annotations.hasAnnotation(JVM_INLINE_ANNOTATION)) {
trace.report(Errors.VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION.on(inlineOrValueKeyword))
}
}

private fun KotlinType.isInapplicableParameterType() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public open class KFooZ : test.IFoo<test.Z> {
public open fun foo(): test.Z
}

public final inline class Z {
public final value class Z {
public constructor Z(/*0*/ kotlin.Int)
public final val value: kotlin.Int
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ annotation class JvmInline
@JvmInline
value class Foo(val x: Int)

<!WRONG_MODIFIER_TARGET!>value<!> interface InlineInterface
<!WRONG_MODIFIER_TARGET!>value<!> annotation class InlineAnn
<!WRONG_MODIFIER_TARGET!>value<!> object InlineObject
<!WRONG_MODIFIER_TARGET!>value<!> enum class InlineEnum
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, WRONG_MODIFIER_TARGET!>value<!> interface InlineInterface
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, WRONG_MODIFIER_TARGET!>value<!> annotation class InlineAnn
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, WRONG_MODIFIER_TARGET!>value<!> object InlineObject
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, WRONG_MODIFIER_TARGET!>value<!> enum class InlineEnum
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ package kotlin {

public final value annotation class InlineAnn : kotlin.Annotation {
public constructor InlineAnn()
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 open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

public final value enum class InlineEnum : kotlin.Enum<kotlin.InlineEnum> {
Expand All @@ -27,24 +27,24 @@ package kotlin {
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<kotlin.InlineEnum!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String

// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): kotlin.InlineEnum
public final /*synthesized*/ fun values(): kotlin.Array<kotlin.InlineEnum>
}

public value interface InlineInterface {
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 open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

public value object InlineObject {
private constructor InlineObject()
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 open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

public final annotation class JvmInline : kotlin.Annotation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ annotation class JvmInline

<!UNSUPPORTED_FEATURE, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class Foo(val x: Int)

<!WRONG_MODIFIER_TARGET!>value<!> annotation class InlineAnn
<!WRONG_MODIFIER_TARGET!>value<!> object InlineObject
<!WRONG_MODIFIER_TARGET!>value<!> enum class InlineEnum
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, WRONG_MODIFIER_TARGET!>value<!> annotation class InlineAnn
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, WRONG_MODIFIER_TARGET!>value<!> object InlineObject
<!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, WRONG_MODIFIER_TARGET!>value<!> enum class InlineEnum

@JvmInline
<!UNSUPPORTED_FEATURE!>value<!> class NotVal(<!INLINE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER!>x: Int<!>)
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ package kotlin {
public final value class Foo {
public constructor Foo(/*0*/ x: kotlin.Int)
public final val x: kotlin.Int
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 open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

public final value annotation class InlineAnn : kotlin.Annotation {
public constructor InlineAnn()
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 open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

public final value enum class InlineEnum : kotlin.Enum<kotlin.InlineEnum> {
Expand All @@ -27,7 +27,7 @@ package kotlin {
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<kotlin.InlineEnum!>!
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String

// Static members
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): kotlin.InlineEnum
Expand All @@ -36,9 +36,9 @@ package kotlin {

public value object InlineObject {
private constructor InlineObject()
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 open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

public final annotation class JvmInline : kotlin.Annotation {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// !LANGUAGE: +InlineClasses

package kotlin

annotation class JvmInline

@JvmInline
inline class IC(val a: Any)

@JvmInline
value class VC(val a: Any)

@JvmInline
class C

@JvmInline
interface I

@JvmInline
object O

@JvmInline
data class DC(val a: Any)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// !LANGUAGE: +InlineClasses

package kotlin

annotation class JvmInline

<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
inline class IC(val a: Any)

@JvmInline
value class VC(val a: Any)

<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
class C

<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
interface I

<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
object O

<!JVM_INLINE_WITHOUT_VALUE_CLASS!>@JvmInline<!>
data class DC(val a: Any)
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package

package kotlin {

@kotlin.JvmInline public final class C {
public constructor C()
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
}

@kotlin.JvmInline public final data class DC {
public constructor DC(/*0*/ a: kotlin.Any)
public final val a: kotlin.Any
public final operator /*synthesized*/ fun component1(): kotlin.Any
public final /*synthesized*/ fun copy(/*0*/ a: kotlin.Any = ...): kotlin.DC
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

@kotlin.JvmInline public interface I {
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
}

@kotlin.JvmInline public final inline class IC {
public constructor IC(/*0*/ a: kotlin.Any)
public final val a: kotlin.Any
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}

public final annotation class JvmInline : kotlin.Annotation {
public constructor JvmInline()
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
}

@kotlin.JvmInline public object O {
private constructor O()
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
}

@kotlin.JvmInline public final value class VC {
public constructor VC(/*0*/ a: kotlin.Any)
public final val a: kotlin.Any
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ object B2 {

@JvmInline
final value class D0(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>open<!> value class D1(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>abstract<!> value class D2(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>sealed<!> value class D3(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>open<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D1(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>abstract<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D2(val x: Int)
<!INLINE_CLASS_NOT_FINAL!>sealed<!> <!VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> class D3(val x: Int)

<!INCOMPATIBLE_MODIFIERS, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class D4(val x: String)
<!INCOMPATIBLE_MODIFIERS, VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION!>value<!> <!INCOMPATIBLE_MODIFIERS!>data<!> class <!CONFLICTING_JVM_DECLARATIONS, CONFLICTING_JVM_DECLARATIONS, CONFLICTING_JVM_DECLARATIONS!>D4(val x: String)<!>
Loading

0 comments on commit ca3e7cf

Please sign in to comment.