Support boxing/unboxing for captured vars of inline class types

This commit is contained in:
Mikhail Zarechenskiy
2018-02-07 04:49:06 +03:00
parent 9f24bbd980
commit fefcddc803
14 changed files with 228 additions and 79 deletions
@@ -76,6 +76,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.kotlin.types.TypeProjection;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
@@ -2591,9 +2592,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return result;
}
Type currentScriptType = typeMapper.mapType(scriptContext.getScriptDescriptor());
Type classType = typeMapper.mapType(receiver);
SimpleType receiverKotlinType = receiver.getDefaultType();
Type classType = typeMapper.mapType(receiverKotlinType);
String fieldName = scriptContext.getScriptFieldName(receiver);
return StackValue.field(classType, currentScriptType, fieldName, false, result, receiver);
return StackValue.field(classType, receiverKotlinType, currentScriptType, fieldName, false, result, receiver);
}
result = cur.getOuterExpression(result, false);
@@ -1008,8 +1008,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void copyFieldFromCompanionObject(PropertyDescriptor propertyDescriptor) {
ExpressionCodegen codegen = createOrGetClInitCodegen();
StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, false, null, StackValue.none());
StackValue.Field field = StackValue
.field(property.type, classAsmType, propertyDescriptor.getName().asString(), true, StackValue.none(), propertyDescriptor);
StackValue.Field field = StackValue.field(
property.type, property.kotlinType, classAsmType, propertyDescriptor.getName().asString(),
true, StackValue.none(), propertyDescriptor
);
field.store(property, codegen.v);
}
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
@@ -285,24 +286,25 @@ public abstract class StackValue {
@NotNull
public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) {
return field(type, owner, name, isStatic, receiver, null);
return field(type, null, owner, name, isStatic, receiver, null);
}
@NotNull
public static Field field(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull Type owner,
@NotNull String name,
boolean isStatic,
@NotNull StackValue receiver,
@Nullable DeclarationDescriptor descriptor
) {
return new Field(type, owner, name, isStatic, receiver, descriptor);
return new Field(type, kotlinType, owner, name, isStatic, receiver, descriptor);
}
@NotNull
public static Field field(@NotNull StackValue.Field field, @NotNull StackValue newReceiver) {
return field(field.type, field.owner, field.name, field.isStaticPut, newReceiver, field.descriptor);
return field(field.type, field.kotlinType, field.owner, field.name, field.isStaticPut, newReceiver, field.descriptor);
}
@NotNull
@@ -540,7 +542,7 @@ public abstract class StackValue {
@NotNull StackValue receiver,
@Nullable DeclarationDescriptor descriptor
) {
return field(sharedTypeForType(localType), classType, fieldName, false, receiver, descriptor);
return field(sharedTypeForType(localType), null, classType, fieldName, false, receiver, descriptor);
}
public static FieldForSharedVar fieldForSharedVar(
@@ -703,8 +705,9 @@ public abstract class StackValue {
public static Field enumEntry(@NotNull ClassDescriptor descriptor, @NotNull KotlinTypeMapper typeMapper) {
DeclarationDescriptor enumClass = descriptor.getContainingDeclaration();
assert DescriptorUtils.isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + descriptor;
Type type = typeMapper.mapType((ClassDescriptor) enumClass);
return field(type, type, descriptor.getName().asString(), true, none(), descriptor);
SimpleType enumType = ((ClassDescriptor) enumClass).getDefaultType();
Type type = typeMapper.mapType(enumType);
return field(type, enumType, type, descriptor.getName().asString(), true, none(), descriptor);
}
@NotNull
@@ -1267,13 +1270,14 @@ public abstract class StackValue {
public Field(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull Type owner,
@NotNull String name,
boolean isStatic,
@NotNull StackValue receiver,
@Nullable DeclarationDescriptor descriptor
) {
super(type, null, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
super(type, kotlinType, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
this.owner = owner;
this.name = name;
this.descriptor = descriptor;
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2015 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.context;
@@ -22,6 +11,7 @@ import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.codegen.StackValue;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.types.SimpleType;
import static org.jetbrains.kotlin.codegen.AsmUtil.CAPTURED_THIS_FIELD;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
@@ -51,8 +41,10 @@ public class ClassContext extends FieldOwnerContext<ClassDescriptor> {
if (!canHaveOuter(typeMapper.getBindingContext(), getContextDescriptor())) return null;
SimpleType enclosingClassType = enclosingClass.getDefaultType();
return StackValue.field(
typeMapper.mapType(enclosingClass),
typeMapper.mapType(enclosingClassType),
enclosingClassType,
typeMapper.mapType(getContextDescriptor()),
CAPTURED_THIS_FIELD,
/* isStatic = */ false,
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2015 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.context;
@@ -61,8 +50,10 @@ public interface LocalLookup {
? JvmCodegenUtil.getPropertyDelegateType((VariableDescriptorWithAccessors) vd, state.getBindingContext())
: null;
Type sharedVarType = state.getTypeMapper().getSharedVarType(vd);
Type localType = state.getTypeMapper().mapType(delegateType != null ? delegateType : vd.getType());
KotlinType localKotlinType = delegateType != null ? delegateType : vd.getType();
Type localType = state.getTypeMapper().mapType(localKotlinType);
Type type = sharedVarType != null ? sharedVarType : localType;
KotlinType kotlinType = sharedVarType != null ? null : localKotlinType;
String fieldName = "$" + vd.getName();
StackValue.Local thiz = StackValue.LOCAL_0;
@@ -75,7 +66,7 @@ public interface LocalLookup {
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, wrapperValue, type);
}
else {
innerValue = StackValue.field(type, classType, fieldName, false, thiz, vd);
innerValue = StackValue.field(type, kotlinType, classType, fieldName, false, thiz, vd);
enclosedValueDescriptor = new EnclosedValueDescriptor(fieldName, d, innerValue, type);
}
@@ -114,7 +105,7 @@ public interface LocalLookup {
if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
// This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
// (instead of passing this instance to the constructor and storing as a field)
return StackValue.field(localType, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0, vd);
return StackValue.field(localType, null, localType, JvmAbi.INSTANCE_FIELD, true, StackValue.LOCAL_0, vd);
}
String internalName = localType.getInternalName();
@@ -123,8 +114,9 @@ public interface LocalLookup {
String localFunSuffix = localClassIndexStart >= 0 ? simpleName.substring(localClassIndexStart) : "";
String fieldName = "$" + vd.getName() + localFunSuffix;
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(localType, classType, fieldName, false,
StackValue.LOCAL_0, vd);
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(
localType, null, classType, fieldName, false, StackValue.LOCAL_0, vd
);
closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType));
@@ -152,8 +144,9 @@ public interface LocalLookup {
KotlinType receiverType = closure.getEnclosingReceiverDescriptor().getType();
Type type = state.getTypeMapper().mapType(receiverType);
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(type, classType, CAPTURED_RECEIVER_FIELD, false,
StackValue.LOCAL_0, d);
StackValue.StackValueWithSimpleReceiver innerValue = StackValue.field(
type, receiverType, classType, CAPTURED_RECEIVER_FIELD, false, StackValue.LOCAL_0, d
);
closure.setCaptureReceiver();
return innerValue;
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2015 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.inline
@@ -28,6 +17,8 @@ import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.SmartSet
import org.jetbrains.org.objectweb.asm.Label
@@ -205,8 +196,13 @@ class MethodInliner(
return
}
val valueParameters =
listOfNotNull(info.invokeMethodDescriptor.extensionReceiverParameter) + info.invokeMethodDescriptor.valueParameters
val valueParamShift = Math.max(nextLocalIndex, markerShift)//NB: don't inline cause it changes
putStackValuesIntoLocals(listOf(*info.invokeMethod.argumentTypes), valueParamShift, this, desc)
putStackValuesIntoLocalsForLambdaOnInvoke(
listOf(*info.invokeMethod.argumentTypes), valueParameters, valueParamShift, this, desc
)
if (invokeCall.lambdaInfo.invokeMethodDescriptor.valueParameters.isEmpty()) {
// There won't be no parameters processing and line call can be left without actual instructions.
@@ -248,8 +244,11 @@ class MethodInliner(
result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages)
//return value boxing/unboxing
val bridge = typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.invokeMethodDescriptor))
StackValue.onStack(info.invokeMethod.returnType).put(bridge.returnType, this)
val erasedInvokeFunction = ClosureCodegen.getErasedInvokeFunction(info.invokeMethodDescriptor)
val bridge = typeMapper.mapAsmMethod(erasedInvokeFunction)
StackValue
.onStack(info.invokeMethod.returnType, info.invokeMethodDescriptor.returnType)
.put(bridge.returnType, erasedInvokeFunction.returnType, this)
setLambdaInlining(false)
addInlineMarker(this, false)
childSourceMapper.endMapping()
@@ -889,8 +888,12 @@ class MethodInliner(
}
}
private fun putStackValuesIntoLocals(
directOrder: List<Type>, shift: Int, iv: InstructionAdapter, descriptor: String
private fun putStackValuesIntoLocalsForLambdaOnInvoke(
directOrder: List<Type>,
directOrderOfArguments: List<ParameterDescriptor>,
shift: Int,
iv: InstructionAdapter,
descriptor: String
) {
val actualParams = Type.getArgumentTypes(descriptor)
assert(actualParams.size == directOrder.size) {
@@ -899,11 +902,18 @@ class MethodInliner(
var currentShift = shift + directOrder.sumBy { it.size }
val safeToUseArgumentKotlinType = directOrder.size == directOrderOfArguments.size
directOrder.asReversed().forEachIndexed { index, type ->
currentShift -= type.size
val typeOnStack = actualParams[index]
if (typeOnStack != type) {
StackValue.onStack(typeOnStack).put(type, iv)
val argumentType = if (safeToUseArgumentKotlinType)
directOrderOfArguments[index].type.takeIf { it.isInlineClassType() }
else
null
// if argument type had inline class type then after substitution it will also have the same type,
// but probably boxed, which is OK because in terms of Kotlin types this is the same type
StackValue.onStack(typeOnStack, argumentType).put(type, argumentType, iv)
}
iv.store(currentShift, type)
}
@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.codegen
@@ -339,12 +328,13 @@ class ExpressionCodegen(
val propertyDescriptor = expression.descriptor
val realDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor)
val fieldType = typeMapper.mapType(realDescriptor.original.type)
val fieldKotlinType = realDescriptor.original.type
val fieldType = typeMapper.mapType(fieldKotlinType)
val ownerType = typeMapper.mapImplementationOwner(propertyDescriptor)
val fieldName = propertyDescriptor.name.asString()
val isStatic = expression.receiver == null // TODO
return StackValue.field(fieldType, ownerType, fieldName, isStatic, receiverValue, realDescriptor)
return StackValue.field(fieldType, fieldKotlinType, ownerType, fieldName, isStatic, receiverValue, realDescriptor)
}
override fun visitGetField(expression: IrGetField, data: BlockInfo): StackValue {
@@ -0,0 +1,71 @@
// !LANGUAGE: +InlineClasses
inline class UInt(private val value: Int) {
operator fun plus(other: UInt): UInt = UInt(value + other.asValue())
fun asValue(): Int = value
}
val Int.u get() = UInt(this)
var global = 0.u
fun testInlined(x: UInt?, withAssert: Boolean) {
x?.myLet {
takeUInt(it)
takeUInt(x)
}
x?.myLet {
takeNullableUInt(it)
takeNullableUInt(x)
}
if (withAssert) {
x!!.myLet {
takeUInt(it)
takeUInt(x)
}
}
}
fun testNotInlined(x: UInt?) {
x?.myLet {
takeUInt(it)
takeUInt(x)
}
x?.myLet {
takeNullableUInt(it)
takeNullableUInt(x)
}
}
fun takeUInt(y: UInt) {
global += y
}
fun takeNullableUInt(y: UInt?) {
if (y != null) {
global += y
}
}
inline fun <T> T.myLet(f: (T) -> Unit) = f(this)
fun <T> T.nonInlineLet(f: (T) -> Unit) = f(this)
fun box(): String {
val u = 1.u
testInlined(u, true)
if (global.asValue() != 6) return "fail 1"
global = 0.u
testInlined(null, false)
if (global.asValue() != 0) return "fail 2"
global = 0.u
testNotInlined(u)
if (global.asValue() != 4) return "fail 3"
return "OK"
}
@@ -0,0 +1,31 @@
// !LANGUAGE: +InlineClasses
inline class UInt(val value: Int)
fun test(x: UInt?) {
x?.myLet { // unbox
takeUInt(it)
takeUInt(x) // unbox
}
x?.myLet { // unbox
takeNullableUInt(it) // box
takeNullableUInt(x)
}
x!!.myLet { // unbox
takeUInt(it)
takeUInt(x) // unbox
}
}
fun takeUInt(y: UInt) {}
fun takeNullableUInt(y: UInt?) {}
inline fun <T> T.myLet(f: (T) -> Unit) = f(this)
// 1 INVOKESTATIC UInt\$Erased.box
// 5 INVOKEVIRTUAL UInt.unbox
// 0 intValue
// 0 valueOf
@@ -10335,6 +10335,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
doTest(fileName);
}
@TestMetadata("computablePropertyInsideInlineClass.kt")
public void testComputablePropertyInsideInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
doTest(fileName);
}
@TestMetadata("emptyConstructorForInlineClass.kt")
public void testEmptyConstructorForInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
@@ -10335,6 +10335,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
doTest(fileName);
}
@TestMetadata("computablePropertyInsideInlineClass.kt")
public void testComputablePropertyInsideInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
doTest(fileName);
}
@TestMetadata("emptyConstructorForInlineClass.kt")
public void testEmptyConstructorForInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
@@ -1944,6 +1944,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest(fileName);
}
@TestMetadata("inlineClassBoxingUnboxingInsideInlinedLambda.kt")
public void testInlineClassBoxingUnboxingInsideInlinedLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassBoxingUnboxingInsideInlinedLambda.kt");
doTest(fileName);
}
@TestMetadata("inlineClassCallsDefaultValue.kt")
public void testInlineClassCallsDefaultValue() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/inlineClassCallsDefaultValue.kt");
@@ -10335,6 +10335,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
doTest(fileName);
}
@TestMetadata("computablePropertyInsideInlineClass.kt")
public void testComputablePropertyInsideInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
doTest(fileName);
}
@TestMetadata("emptyConstructorForInlineClass.kt")
public void testEmptyConstructorForInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");
@@ -11295,6 +11295,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("boxUnboxOfInlineClassForCapturedVars.kt")
public void testBoxUnboxOfInlineClassForCapturedVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/boxUnboxOfInlineClassForCapturedVars.kt");
doTest(fileName);
}
@TestMetadata("computablePropertyInsideInlineClass.kt")
public void testComputablePropertyInsideInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/computablePropertyInsideInlineClass.kt");
doTest(fileName);
}
@TestMetadata("emptyConstructorForInlineClass.kt")
public void testEmptyConstructorForInlineClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/emptyConstructorForInlineClass.kt");