JS IR: make CodeCleaner more conservative

The CodeCleaner treated all expressions with type `Nothing` as
non-terminating. This is not true for cases when return type is generic,
e.g:

```
fun <T> foo(): T = Any() as T

foo<Nothing>() // type: Nothing
```

This change makes the CodeCleaner more conservative, so that it doesn't
treat to such functions as non-terminating. This eliminates the need
to change call types from Nothing to Unit in
KotlinNothingValueExceptionLowering.
This commit is contained in:
Anton Bannykh
2020-04-30 18:42:35 +03:00
parent 8809abdbac
commit b5f31a3d76
2 changed files with 26 additions and 24 deletions
@@ -38,36 +38,14 @@ class KotlinNothingValueExceptionLowering(
// call ThrowKotlinNothingValueException(): Nothing
// }: Nothing
//
// Changing type of 'foo' to 'kotlin.Unit' is requires so that the 'ThrowKotlinNothingValueException(): Nothing'
// is not considered dead code and is not removed.
// Note that type 'kotlin.Nothing' might be inferred in some cases of projected types.
// See KT-30330 for an example of such code where call of type 'kotlin.Nothing' terminates and produces some value
// (although doing so by subverting the type system).
backendContext.createIrBuilder(parent, expression.startOffset, expression.endOffset).run {
irBlock(expression, null, context.irBuiltIns.nothingType) {
+super.visitCall(changeTypeToUnit(expression))
+super.visitCall(expression)
+irCall(backendContext.ir.symbols.ThrowKotlinNothingValueException)
}
}
} else {
super.visitCall(expression)
}
private fun changeTypeToUnit(call: IrCall): IrCall =
IrCallImpl(
call.startOffset, call.endOffset,
backendContext.irBuiltIns.unitType,
call.symbol,
call.typeArgumentsCount, call.valueArgumentsCount, call.origin, call.superQualifierSymbol
).also { newCall ->
for (i in 0 until call.typeArgumentsCount) {
newCall.putTypeArgument(i, call.getTypeArgument(i))
}
newCall.dispatchReceiver = call.dispatchReceiver
newCall.extensionReceiver = call.extensionReceiver
for (i in 0 until call.valueArgumentsCount) {
newCall.putValueArgument(i, call.getValueArgument(i))
}
}
}
}