Fix runtime CCE in case of out-projected SAM

Probably, when NI is there this fix will become unnecessary because
there will be no approximation applied, thus the value parameter
will remain Hello<#Captured> instead of Nothing

 #KT-17171 Fixed
This commit is contained in:
Denis Zharkov
2018-02-12 12:09:17 +03:00
parent 6baf937a52
commit c47c1c5ffd
7 changed files with 113 additions and 11 deletions
@@ -17,13 +17,34 @@
package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
public class SamType {
@Nullable
public static SamType createByValueParameter(@NotNull ValueParameterDescriptor valueParameter) {
KotlinType originalTypeToUse =
// This can be true in case when the value parameter is in the method of a generic type with out-projection.
// We approximate Inv<Captured#1> to Nothing, while Inv itself can be a SAM interface safe to call here
// (see testData genericSamProjectedOut.kt for details)
KotlinBuiltIns.isNothing(valueParameter.getType())
// In such a case we can't have a proper supertype since wildcards are not allowed there,
// so we use Nothing arguments instead that leads to a raw type used for a SAM wrapper.
// See org.jetbrains.kotlin.codegen.state.KotlinTypeMapper#writeGenericType to understand how
// raw types and Nothing arguments relate.
? TypeUtilsKt.replaceArgumentsWithNothing(valueParameter.getOriginal().getType())
: valueParameter.getType();
return create(TypeMapperUtilsKt.removeExternalProjections(originalTypeToUse));
}
public static SamType create(@NotNull KotlinType originalType) {
if (!SingleAbstractMethodUtils.isSamType(originalType)) return null;
return new SamType(originalType);
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.cfg.WhenChecker;
import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.codegen.when.SwitchCodegenProvider;
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
@@ -608,7 +607,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
ValueParameterDescriptor adaptedParameter = descriptor.getValueParameters().get(valueParameter.getIndex());
if (KotlinTypeChecker.DEFAULT.equalTypes(adaptedParameter.getType(), valueParameter.getType())) continue;
SamType samType = SamType.create(TypeMapperUtilsKt.removeExternalProjections(valueParameter.getType()));
SamType samType = SamType.createByValueParameter(valueParameter);
if (samType == null) continue;
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
@@ -648,7 +647,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
@Override
public void visitConstructorDelegationCall(@NotNull KtConstructorDelegationCall call) {
withinUninitializedClass(call, () -> super.visitConstructorDelegationCall(call));
checkSamCall(call);
}
@@ -692,7 +691,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) operationDescriptor);
if (original == null) return;
SamType samType = SamType.create(original.getValueParameters().get(0).getType());
SamType samType = SamType.createByValueParameter(original.getValueParameters().get(0));
if (samType == null) return;
IElementType token = expression.getOperationToken();
@@ -718,7 +717,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
List<KtExpression> indexExpressions = expression.getIndexExpressions();
List<ValueParameterDescriptor> parameters = original.getValueParameters();
for (ValueParameterDescriptor valueParameter : parameters) {
SamType samType = SamType.create(valueParameter.getType());
SamType samType = SamType.createByValueParameter(valueParameter);
if (samType == null) continue;
if (isSetter && valueParameter.getIndex() == parameters.size() - 1) {