Nullability assertions for extension receiver

In Kotlin 1.1 and before, there were no nullability assertions on
extension receivers, because receiver is resolved with NO_EXPECTED_TYPE.
So, if an expression of platform type is passed as an extension receiver
to a non-private function, it would fail with IllegalArgumentException.
However, if the function is private, then we generated no parameter
assertions under assumption that such function can be called from Kotlin
only, and all arguments are checked on the call site. Thus 'null' could
propagate indefinitely.

In Kotlin 1.2, we do the following:
- Generate nullability assertions for expression receivers.
NB nullability assertions are stored for ReceiverValue instances, not
for expressions: given expression can act as receiver in different
calls, each with an expected receiver type of its own.
- Generate nullability assertions for extension receivers of private
operator functions.
NB it still can throw NPE for some particular "optimized" cases, but at
least those nulls would not propagate indefinitely.

This behavior is disabled by an "advanced" command-line option
'-Xno-receiver-assertions'.
This commit is contained in:
Dmitry Petrov
2017-07-21 17:42:18 +03:00
parent 2427b2cc6c
commit 5d44e095c8
26 changed files with 563 additions and 21 deletions
@@ -93,9 +93,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
)
var additionalJavaModules: Array<String>? by FreezableVar(null)
@Argument(value = "-Xno-call-assertions", description = "Don't generate not-null assertion after each invocation of method returning not-null")
@Argument(value = "-Xno-call-assertions", description = "Don't generate not-null assertions for arguments of platform types")
var noCallAssertions: Boolean by FreezableVar(false)
@Argument(value = "-Xno-receiver-assertions", description = "Don't generate not-null assertion for extension receiver arguments of platform types")
var noReceiverAssertions: Boolean by FreezableVar(false)
@Argument(value = "-Xno-param-assertions", description = "Don't generate not-null assertions on parameters of methods accessible from Java")
var noParamAssertions: Boolean by FreezableVar(false)
@@ -341,6 +341,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
private fun putAdvancedOptions(configuration: CompilerConfiguration, arguments: K2JVMCompilerArguments) {
configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, arguments.noCallAssertions)
configuration.put(JVMConfigurationKeys.DISABLE_RECEIVER_ASSERTIONS, arguments.noReceiverAssertions)
configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, arguments.noParamAssertions)
configuration.put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, arguments.noOptimize)
configuration.put(JVMConfigurationKeys.INHERIT_MULTIFILE_PARTS, arguments.inheritMultifileParts)
@@ -358,6 +359,8 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
configuration.put(JVMConfigurationKeys.ADD_BUILT_INS_FROM_COMPILER_TO_DEPENDENCIES, arguments.addCompilerBuiltIns)
configuration.put(JVMConfigurationKeys.CREATE_BUILT_INS_FROM_MODULE_DEPENDENCIES, arguments.loadBuiltInsFromDependencies)
arguments.declarationsOutputPath?.let { configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
}