Skip to content

Commit 5964115

Browse files
yanexSpace Team
authored andcommitted
[fir2ir] Treat code fragments returning 'Nothing' as non-void
By default, the JVM backend maps the 'Nothing' return type to 'Unit' (see 'JavaToKotlinClassMap.mapKotlinToJava'). For code fragments, such behavior is rather unexpected, especially if the 'Nothing' type appeared as a result of a smart cast. The change replaces the return type of 'Nothing'-returning fragments to 'Any?' so it's mapped to debugger-friendly 'Object' instead. ^KT-70860 Fixed
1 parent 2f71bd2 commit 5964115

File tree

7 files changed

+26
-13
lines changed

7 files changed

+26
-13
lines changed

analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/resultNothing.ir.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ MODULE_FRAGMENT
55
CONSTRUCTOR visibility:public returnType:<root>.CodeFragment [primary]
66
BLOCK_BODY
77
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
8-
FUN name:run visibility:public modality:FINAL returnType:kotlin.Nothing
8+
FUN name:run visibility:public modality:FINAL returnType:kotlin.Any?
99
EXPRESSION_BODY
1010
BLOCK type=kotlin.Unit origin=null
1111
CALL 'public final fun call (): kotlin.Nothing declared in <root>.ContextKt' type=kotlin.Nothing origin=null

analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/resultNothing.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ public final class CodeFragment {
1818
MAXLOCALS = 1
1919

2020
// access flags 0x19
21-
public final static run()Ljava/lang/Void;
22-
@Lorg/jetbrains/annotations/NotNull;() // invisible
21+
public final static run()Ljava/lang/Object;
22+
@Lorg/jetbrains/annotations/Nullable;() // invisible
2323
L0
2424
LINENUMBER 24 L0
2525
INVOKESTATIC ContextKt.call ()Ljava/lang/Void;

analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/resultNothingBeforeSmartCast.ir.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ MODULE_FRAGMENT
55
CONSTRUCTOR visibility:public returnType:<root>.CodeFragment [primary]
66
BLOCK_BODY
77
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
8-
FUN name:run visibility:public modality:FINAL returnType:kotlin.Nothing?
8+
FUN name:run visibility:public modality:FINAL returnType:kotlin.Any?
99
VALUE_PARAMETER kind:Regular name:p0 index:0 type:kotlin.String?
1010
EXPRESSION_BODY
1111
BLOCK type=kotlin.Nothing? origin=null

analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/resultNothingBeforeSmartCast.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ public final class CodeFragment {
1818
MAXLOCALS = 1
1919

2020
// access flags 0x19
21-
public final static run(Ljava/lang/String;)Ljava/lang/Void;
21+
public final static run(Ljava/lang/String;)Ljava/lang/Object;
2222
@Lorg/jetbrains/annotations/Nullable;() // invisible
2323
// annotable parameter count: 1 (invisible)
2424
@Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0
2525
L0
2626
LINENUMBER 21 L0
2727
ALOAD 0
28-
CHECKCAST java/lang/Void
2928
ARETURN
3029
L1
3130
LOCALVARIABLE p0 Ljava/lang/String; L0 L1 0

analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/resultNothingSmartCast.ir.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ MODULE_FRAGMENT
55
CONSTRUCTOR visibility:public returnType:<root>.CodeFragment [primary]
66
BLOCK_BODY
77
DELEGATING_CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in kotlin.Any'
8-
FUN name:run visibility:public modality:FINAL returnType:kotlin.Nothing?
8+
FUN name:run visibility:public modality:FINAL returnType:kotlin.Any?
99
VALUE_PARAMETER kind:Regular name:p0 index:0 type:kotlin.String?
1010
EXPRESSION_BODY
1111
BLOCK type=kotlin.Nothing? origin=null

analysis/analysis-api/testData/components/compilerFacility/compilation/codeFragments/resultNothingSmartCast.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ public final class CodeFragment {
1818
MAXLOCALS = 1
1919

2020
// access flags 0x19
21-
public final static run(Ljava/lang/String;)Ljava/lang/Void;
21+
public final static run(Ljava/lang/String;)Ljava/lang/Object;
2222
@Lorg/jetbrains/annotations/Nullable;() // invisible
2323
// annotable parameter count: 1 (invisible)
2424
@Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0
2525
L0
2626
LINENUMBER 21 L0
2727
ALOAD 0
28-
CHECKCAST java/lang/Void
2928
ARETURN
3029
L1
3130
LOCALVARIABLE p0 Ljava/lang/String; L0 L1 0

compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.fir.java.javaElementFinder
3737
import org.jetbrains.kotlin.fir.references.toResolvedValueParameterSymbol
3838
import org.jetbrains.kotlin.fir.scopes.processAllFunctions
3939
import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
40+
import org.jetbrains.kotlin.fir.types.isNothingOrNullableNothing
4041
import org.jetbrains.kotlin.fir.types.resolvedType
4142
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
4243
import org.jetbrains.kotlin.ir.IrBuiltIns
@@ -58,6 +59,8 @@ import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
5859
import org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI
5960
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
6061
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
62+
import org.jetbrains.kotlin.ir.types.IrType
63+
import org.jetbrains.kotlin.ir.types.makeNullable
6164
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
6265
import org.jetbrains.kotlin.ir.util.defaultType
6366
import org.jetbrains.kotlin.ir.util.fileOrNull
@@ -307,17 +310,14 @@ class Fir2IrConverter(
307310
}
308311

309312
IrSimpleFunctionSymbolImpl().let { irSymbol ->
310-
val lastStatement = codeFragment.block.statements.lastOrNull()
311-
val returnType = (lastStatement as? FirExpression)?.resolvedType?.toIrType() ?: builtins.unitType
312-
313313
IrFactoryImpl.createSimpleFunction(
314314
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
315315
IrDeclarationOrigin.DEFINED,
316316
conversionData.methodName,
317317
DescriptorVisibilities.PUBLIC,
318318
isInline = false,
319319
isExpect = false,
320-
returnType,
320+
computeCodeFragmentReturnType(codeFragment),
321321
Modality.FINAL,
322322
irSymbol,
323323
isTailrec = false,
@@ -356,6 +356,21 @@ class Fir2IrConverter(
356356
return irClass
357357
}
358358

359+
private fun computeCodeFragmentReturnType(codeFragment: FirCodeFragment): IrType {
360+
val lastStatement = codeFragment.block.statements.lastOrNull()
361+
if (lastStatement is FirExpression) {
362+
val lastStatementType = lastStatement.resolvedType
363+
if (lastStatementType.isNothingOrNullableNothing) {
364+
// Unless the last statement type is explicitly 'Unit', treat code fragments like they have a return value.
365+
return builtins.anyType.makeNullable()
366+
}
367+
368+
return lastStatementType.toIrType()
369+
}
370+
371+
return builtins.unitType
372+
}
373+
359374
// `irClass` is a source class and definitely is not a lazy class
360375
@OptIn(UnsafeDuringIrConstructionAPI::class)
361376
private fun delegatedMembers(irClass: IrClass): List<FirDeclaration> {

0 commit comments

Comments
 (0)