Emit not-null assertions for enhanced types
This commit is contained in:
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.load.java.JavaVisibilities;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
|
||||
@@ -45,7 +46,6 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPackage;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.kotlin.types.Approximation;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypesPackage;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
@@ -637,10 +637,10 @@ public class AsmUtil {
|
||||
public static StackValue genNotNullAssertions(
|
||||
@NotNull GenerationState state,
|
||||
@NotNull final StackValue stackValue,
|
||||
@Nullable final Approximation.Info approximationInfo
|
||||
@Nullable final RuntimeAssertionInfo runtimeAssertionInfo
|
||||
) {
|
||||
if (!state.isCallAssertionsEnabled()) return stackValue;
|
||||
if (approximationInfo == null || !TypesPackage.assertNotNull(approximationInfo)) return stackValue;
|
||||
if (runtimeAssertionInfo == null || !runtimeAssertionInfo.getNeedNotNullAssertion()) return stackValue;
|
||||
|
||||
return new StackValue(stackValue.type) {
|
||||
|
||||
@@ -649,7 +649,7 @@ public class AsmUtil {
|
||||
stackValue.put(type, v);
|
||||
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
|
||||
v.dup();
|
||||
v.visitLdcInsn(approximationInfo.getMessage());
|
||||
v.visitLdcInsn(runtimeAssertionInfo.getMessage());
|
||||
v.invokestatic("kotlin/jvm/internal/Intrinsics", "checkExpressionValueIsNotNull",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)V", false);
|
||||
}
|
||||
|
||||
@@ -49,10 +49,12 @@ import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.ScriptCodeDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.jvm.bindingContextSlices.BindingContextSlicesPackage;
|
||||
import org.jetbrains.kotlin.lexer.JetTokens;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
@@ -75,7 +77,6 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
|
||||
import org.jetbrains.kotlin.types.Approximation;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypeProjection;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
@@ -280,12 +281,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
StackValue stackValue = selector.accept(visitor, receiver);
|
||||
|
||||
Approximation.Info approximationInfo = null;
|
||||
RuntimeAssertionInfo runtimeAssertionInfo = null;
|
||||
if (selector instanceof JetExpression) {
|
||||
approximationInfo = bindingContext.get(BindingContext.EXPRESSION_RESULT_APPROXIMATION, (JetExpression) selector);
|
||||
runtimeAssertionInfo = bindingContext.get(BindingContextSlicesPackage.getRUNTIME_ASSERTION_INFO(), (JetExpression) selector);
|
||||
}
|
||||
|
||||
return genNotNullAssertions(state, stackValue, approximationInfo);
|
||||
return genNotNullAssertions(state, stackValue, runtimeAssertionInfo);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
|
||||
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction;
|
||||
@@ -51,8 +52,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.types.Approximation;
|
||||
import org.jetbrains.kotlin.types.TypesPackage;
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
@@ -834,10 +833,10 @@ public class FunctionCodegen {
|
||||
StackValue stackValue = AsmUtil.genNotNullAssertions(
|
||||
state,
|
||||
StackValue.onStack(delegateToMethod.getReturnType()),
|
||||
TypesPackage.getApproximationTo(
|
||||
delegatedTo.getReturnType(),
|
||||
RuntimeAssertionInfo.create(
|
||||
delegateFunction.getReturnType(),
|
||||
new Approximation.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")
|
||||
delegatedTo.getReturnType(),
|
||||
new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.jvm.bindingContextSlices.RUNTIME_ASSERTION_INFO
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
import kotlin.platform.platformStatic
|
||||
|
||||
public class RuntimeAssertionInfo(public val needNotNullAssertion: Boolean, public val message: String) {
|
||||
public interface DataFlowExtras {
|
||||
class OnlyMessage(message: String) : DataFlowExtras {
|
||||
override val canBeNull: Boolean get() = true
|
||||
override val possibleTypes: Set<JetType> get() = setOf()
|
||||
override val presentableText: String = message
|
||||
}
|
||||
|
||||
val canBeNull: Boolean
|
||||
val possibleTypes: Set<JetType>
|
||||
val presentableText: String
|
||||
}
|
||||
|
||||
companion object {
|
||||
platformStatic public fun create(
|
||||
expectedType: JetType,
|
||||
expressionType: JetType,
|
||||
dataFlowExtras: DataFlowExtras
|
||||
): RuntimeAssertionInfo? {
|
||||
fun assertNotNull(): Boolean {
|
||||
if (expectedType.isError() || expressionType.isError()) return false
|
||||
|
||||
// T : Any, T! = T..T?
|
||||
// Let T$ will be copy of T! with enhanced nullability.
|
||||
// Cases when nullability assertion needed: T! -> T, T$ -> T
|
||||
|
||||
// Expected type either T?, T! or T$
|
||||
if (TypeUtils.isNullableType(expectedType) || expectedType.hasEnhancedNullability()) return false
|
||||
|
||||
// Expression type is not nullable and not enhanced (neither T?, T! or T$)
|
||||
val isExpressionTypeNullable = TypeUtils.isNullableType(expressionType)
|
||||
if (!isExpressionTypeNullable && !expressionType.hasEnhancedNullability()) return false
|
||||
|
||||
// Smart-cast T! or T?
|
||||
if (!dataFlowExtras.canBeNull && isExpressionTypeNullable) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return if (assertNotNull())
|
||||
RuntimeAssertionInfo(needNotNullAssertion = true, message = dataFlowExtras.presentableText)
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
private fun JetType.hasEnhancedNullability()
|
||||
= getAnnotations().findAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) != null
|
||||
}
|
||||
}
|
||||
|
||||
public object RuntimeAssertionsTypeChecker : AdditionalTypeChecker {
|
||||
override fun checkType(expression: JetExpression, expressionType: JetType, c: ResolutionContext<*>) {
|
||||
if (TypeUtils.noExpectedType(c.expectedType)) return
|
||||
|
||||
val assertionInfo = RuntimeAssertionInfo.create(
|
||||
c.expectedType,
|
||||
expressionType,
|
||||
object : RuntimeAssertionInfo.DataFlowExtras {
|
||||
override val canBeNull: Boolean
|
||||
get() = c.dataFlowInfo.getNullability(dataFlowValue).canBeNull()
|
||||
override val possibleTypes: Set<JetType>
|
||||
get() = c.dataFlowInfo.getPossibleTypes(dataFlowValue)
|
||||
override val presentableText: String
|
||||
get() = StringUtil.trimMiddle(expression.getText(), 50)
|
||||
|
||||
private val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c)
|
||||
}
|
||||
)
|
||||
|
||||
if (assertionInfo != null) {
|
||||
c.trace.record(RUNTIME_ASSERTION_INFO, expression, assertionInfo)
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkReceiver(
|
||||
receiverParameter: ReceiverParameterDescriptor,
|
||||
receiverArgument: ReceiverValue,
|
||||
safeAccess: Boolean,
|
||||
c: CallResolutionContext<*>
|
||||
) { }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.bindingContextSlices
|
||||
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.util.slicedMap.BasicWritableSlice
|
||||
import org.jetbrains.kotlin.util.slicedMap.RewritePolicy
|
||||
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
||||
import org.jetbrains.kotlin.utils.DO_NOTHING
|
||||
|
||||
public val RUNTIME_ASSERTION_INFO: WritableSlice<JetExpression, RuntimeAssertionInfo> = BasicWritableSlice(RewritePolicy.DO_NOTHING)
|
||||
+2
-1
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.cfg.WhenChecker
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionsTypeChecker
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNotNull
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNullable
|
||||
@@ -63,7 +64,7 @@ public class KotlinJvmCheckerProvider(private val module: ModuleDescriptor) : Ad
|
||||
JavaAnnotationMethodCallChecker(), TraitDefaultMethodCallChecker(),
|
||||
ReflectionAPICallChecker(module)),
|
||||
|
||||
additionalTypeCheckers = listOf(JavaNullabilityWarningsChecker()),
|
||||
additionalTypeCheckers = listOf(JavaNullabilityWarningsChecker(), RuntimeAssertionsTypeChecker),
|
||||
additionalSymbolUsageValidators = listOf()
|
||||
)
|
||||
|
||||
|
||||
@@ -45,10 +45,10 @@ fun checkAssertions(illegalStateExpected: Boolean) {
|
||||
check("plus") { A() + A() }
|
||||
|
||||
// field
|
||||
// check("NULL") { A().NULL }
|
||||
check("NULL") { A().NULL }
|
||||
|
||||
// static field
|
||||
// check("STATIC_NULL") { A.STATIC_NULL }
|
||||
check("STATIC_NULL") { A.STATIC_NULL }
|
||||
|
||||
// postfix expression
|
||||
// TODO:
|
||||
|
||||
@@ -126,6 +126,7 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase {
|
||||
loadFile("notNullAssertions/arrayListGet.kt");
|
||||
String text = generateToText();
|
||||
|
||||
assertTrue(text.contains("checkExpressionValueIsNotNull"));
|
||||
assertTrue(text.contains("checkParameterIsNotNull"));
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase {
|
||||
loadFile("notNullAssertions/javaMultipleSubstitutions.kt");
|
||||
String text = generateToText();
|
||||
|
||||
assertEquals(0, StringUtil.getOccurrenceCount(text, "checkExpressionValueIsNotNull"));
|
||||
assertEquals(3, StringUtil.getOccurrenceCount(text, "checkExpressionValueIsNotNull"));
|
||||
assertEquals(3, StringUtil.getOccurrenceCount(text, "checkParameterIsNotNull"));
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,10 @@ public final class JvmAnnotationNames {
|
||||
|
||||
public static final FqName PURELY_IMPLEMENTS_ANNOTATION = new FqName("kotlin.jvm.PurelyImplements");
|
||||
|
||||
// Just for internal use: there is no such real classes in bytecode
|
||||
public static final FqName ENHANCED_NULLABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedNullability");
|
||||
public static final FqName ENHANCED_MUTABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedMutability");
|
||||
|
||||
public static class KotlinClass {
|
||||
public static final JvmClassName CLASS_NAME = JvmClassName.byInternalName("kotlin/jvm/internal/KotlinClass");
|
||||
public static final ClassId KIND_CLASS_ID =
|
||||
|
||||
+64
-14
@@ -18,12 +18,19 @@ package org.jetbrains.kotlin.load.java.typeEnhacement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.JavaTypeQualifiers
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.MutabilityQualifier.MUTABLE
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.MutabilityQualifier.READ_ONLY
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.NullabilityQualifier.NOT_NULL
|
||||
import org.jetbrains.kotlin.load.java.typeEnhacement.NullabilityQualifier.NULLABLE
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
// The index in the lambda is the position of the type component:
|
||||
@@ -68,7 +75,7 @@ private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, i
|
||||
?: return Result(this, 1)
|
||||
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val enhancedClassifier = originalClass.enhanceMutability(effectiveQualifiers, position)
|
||||
val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
val enhancedArguments = getArguments().mapIndexed {
|
||||
@@ -87,10 +94,17 @@ private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, i
|
||||
}
|
||||
}
|
||||
|
||||
val enhancedType = JetTypeImpl(
|
||||
val (enhancedNullability, enhancedNullabilityAnnotations) = this.getEnhancedNullability(effectiveQualifiers, position)
|
||||
val newAnnotations = listOf(
|
||||
getAnnotations(),
|
||||
enhancedMutabilityAnnotations,
|
||||
enhancedNullabilityAnnotations
|
||||
).filterNotNull().compositeAnnotationsOrSingle()
|
||||
|
||||
val enhancedType = JetTypeImpl(
|
||||
newAnnotations,
|
||||
enhancedClassifier.getTypeConstructor(),
|
||||
this.getEnhancedNullability(effectiveQualifiers, position),
|
||||
enhancedNullability,
|
||||
enhancedArguments,
|
||||
if (enhancedClassifier is ClassDescriptor)
|
||||
enhancedClassifier.getMemberScope(enhancedArguments)
|
||||
@@ -99,36 +113,72 @@ private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, i
|
||||
return Result(enhancedType, globalArgIndex - index)
|
||||
}
|
||||
|
||||
private fun List<Annotations>.compositeAnnotationsOrSingle() = when (size()) {
|
||||
0 -> error("At least one Annotations object expected")
|
||||
1 -> single()
|
||||
else -> CompositeAnnotations(this)
|
||||
}
|
||||
|
||||
private fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
|
||||
|
||||
private fun ClassifierDescriptor.enhanceMutability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): ClassifierDescriptor {
|
||||
if (!position.shouldEnhance()) return this
|
||||
if (this !is ClassDescriptor) return this // mutability is not applicable for type parameters
|
||||
private data class EnhancementResult<T>(val result: T, val enhancementAnnotations: Annotations?)
|
||||
private fun <T> T.noChange() = EnhancementResult(this, null)
|
||||
private fun <T> T.enhancedNullability() = EnhancementResult(this, ENHANCED_NULLABILITY_ANNOTATIONS)
|
||||
private fun <T> T.enhancedMutability() = EnhancementResult(this, ENHANCED_MUTABILITY_ANNOTATIONS)
|
||||
|
||||
private fun ClassifierDescriptor.enhanceMutability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): EnhancementResult<ClassifierDescriptor> {
|
||||
if (!position.shouldEnhance()) return this.noChange()
|
||||
if (this !is ClassDescriptor) return this.noChange() // mutability is not applicable for type parameters
|
||||
|
||||
val mapping = JavaToKotlinClassMap.INSTANCE
|
||||
|
||||
when (qualifiers.mutability) {
|
||||
READ_ONLY -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_LOWER && mapping.isMutable(this)) {
|
||||
return mapping.convertMutableToReadOnly(this)
|
||||
return mapping.convertMutableToReadOnly(this).enhancedMutability()
|
||||
}
|
||||
}
|
||||
MUTABLE -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_UPPER && mapping.isReadOnly(this) ) {
|
||||
return mapping.convertReadOnlyToMutable(this)
|
||||
return mapping.convertReadOnlyToMutable(this).enhancedMutability()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this
|
||||
return this.noChange()
|
||||
}
|
||||
|
||||
private fun JetType.getEnhancedNullability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): Boolean {
|
||||
if (!position.shouldEnhance()) return this.isMarkedNullable()
|
||||
private fun JetType.getEnhancedNullability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): EnhancementResult<Boolean> {
|
||||
if (!position.shouldEnhance()) return this.isMarkedNullable().noChange()
|
||||
|
||||
return when (qualifiers.nullability) {
|
||||
NULLABLE -> true
|
||||
NOT_NULL -> false
|
||||
else -> this.isMarkedNullable()
|
||||
NULLABLE -> true.enhancedNullability()
|
||||
NOT_NULL -> false.enhancedNullability()
|
||||
else -> this.isMarkedNullable().noChange()
|
||||
}
|
||||
}
|
||||
|
||||
private val ENHANCED_NULLABILITY_ANNOTATIONS = EnhancedTypeAnnotations(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION)
|
||||
private val ENHANCED_MUTABILITY_ANNOTATIONS = EnhancedTypeAnnotations(JvmAnnotationNames.ENHANCED_MUTABILITY_ANNOTATION)
|
||||
|
||||
private class EnhancedTypeAnnotations(private val fqNameToMatch: FqName) : Annotations {
|
||||
override fun isEmpty() = false
|
||||
|
||||
override fun findAnnotation(fqName: FqName) = when (fqName) {
|
||||
fqNameToMatch -> EnhancedTypeAnnotationDescriptor
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun findExternalAnnotation(fqName: FqName) = null
|
||||
|
||||
// Note, that this class may break Annotations contract (!isEmpty && iterator.isEmpty())
|
||||
// It's a hack that we need unless we have stable "user data" in JetType
|
||||
override fun iterator(): Iterator<AnnotationDescriptor> = emptyList<AnnotationDescriptor>().iterator()
|
||||
}
|
||||
|
||||
private object EnhancedTypeAnnotationDescriptor : AnnotationDescriptor {
|
||||
private fun throwError() = error("No methods should be called on this descriptor. Only it's presence matters")
|
||||
override fun getType() = throwError()
|
||||
override fun getAllValueArguments() = throwError()
|
||||
override fun toString() = "[EnhancedType]"
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socke
|
||||
stepIntoSpecificKotlinClasses.kt:8
|
||||
MyJavaClass.java:12
|
||||
stepIntoSpecificKotlinClasses.kt:8
|
||||
Intrinsics.!EXT!
|
||||
stepIntoSpecificKotlinClasses.kt:8
|
||||
stepIntoSpecificKotlinClasses.kt:9
|
||||
stepIntoSpecificKotlinClasses.kt:10
|
||||
Thread.!EXT!
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
Reference in New Issue
Block a user