Fix for a problem with smart cast impossible in a situation when it's not needed. A test for KT-3572. #KT-3572 Fixed.

This commit is contained in:
Mikhail Glukhikh
2015-04-30 11:50:38 +03:00
parent 093878bd06
commit f4dd685bbe
5 changed files with 59 additions and 7 deletions
@@ -653,7 +653,9 @@ public class CandidateResolver {
context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument); context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument);
return OTHER_ERROR; return OTHER_ERROR;
} }
SmartCastUtils.recordSmartCastIfNecessary(receiverArgument, receiverParameter.getType(), context, safeAccess); if (!SmartCastUtils.recordSmartCastIfNecessary(receiverArgument, receiverParameter.getType(), context, safeAccess)) {
return OTHER_ERROR;
}
JetType receiverArgumentType = receiverArgument.getType(); JetType receiverArgumentType = receiverArgument.getType();
@@ -158,31 +158,31 @@ public class SmartCastUtils {
return intersection; return intersection;
} }
// Returns false when we need smart cast but cannot do it, otherwise true
public static boolean recordSmartCastIfNecessary( public static boolean recordSmartCastIfNecessary(
@NotNull ReceiverValue receiver, @NotNull ReceiverValue receiver,
@NotNull JetType receiverParameterType, @NotNull JetType receiverParameterType,
@NotNull ResolutionContext context, @NotNull ResolutionContext context,
boolean safeAccess boolean safeAccess
) { ) {
if (!(receiver instanceof ExpressionReceiver)) return false; if (!(receiver instanceof ExpressionReceiver)) return true;
receiverParameterType = safeAccess ? TypeUtils.makeNullable(receiverParameterType) : receiverParameterType; receiverParameterType = safeAccess ? TypeUtils.makeNullable(receiverParameterType) : receiverParameterType;
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(receiver.getType(), receiverParameterType)) { if (ArgumentTypeResolver.isSubtypeOfForArgumentType(receiver.getType(), receiverParameterType)) {
return false; return true;
} }
Collection<JetType> smartCastTypesExcludingReceiver = getSmartCastVariantsExcludingReceiver(context, receiver); Collection<JetType> smartCastTypesExcludingReceiver = getSmartCastVariantsExcludingReceiver(context, receiver);
JetType smartCastSubType = getSmartCastSubType(receiverParameterType, smartCastTypesExcludingReceiver); JetType smartCastSubType = getSmartCastSubType(receiverParameterType, smartCastTypesExcludingReceiver);
if (smartCastSubType == null) return false; if (smartCastSubType == null) return true;
JetExpression expression = ((ExpressionReceiver) receiver).getExpression(); JetExpression expression = ((ExpressionReceiver) receiver).getExpression();
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, context); DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, context);
recordCastOrError(expression, smartCastSubType, context.trace, dataFlowValue.isPredictable(), true); return recordCastOrError(expression, smartCastSubType, context.trace, dataFlowValue.isPredictable(), true);
return true;
} }
public static void recordCastOrError( public static boolean recordCastOrError(
@NotNull JetExpression expression, @NotNull JetExpression expression,
@NotNull JetType type, @NotNull JetType type,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,
@@ -200,6 +200,7 @@ public class SmartCastUtils {
else { else {
trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.getText())); trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.getText()));
} }
return canBeCast;
} }
public static boolean canBeSmartCast( public static boolean canBeSmartCast(
@@ -0,0 +1,17 @@
trait Printer {
fun print()
}
class OKPrinter : Printer {
override fun print() { }
}
class MyClass(var printer: Printer)
fun main(m: MyClass) {
if (m.printer is OKPrinter) {
// We do not need smart cast here, so we should not get SMARTCAST_IMPOSSIBLE
m.printer.print()
}
}
@@ -0,0 +1,26 @@
package
internal fun main(/*0*/ m: MyClass): kotlin.Unit
internal final class MyClass {
public constructor MyClass(/*0*/ printer: Printer)
internal final var printer: Printer
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal final class OKPrinter : Printer {
public constructor OKPrinter()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
internal open override /*1*/ fun print(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
internal trait Printer {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
internal abstract fun print(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -10998,6 +10998,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kt3572.kt")
public void testKt3572() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/kt3572.kt");
doTest(fileName);
}
@TestMetadata("kt3711.kt") @TestMetadata("kt3711.kt")
public void testKt3711() throws Exception { public void testKt3711() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/kt3711.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/kt3711.kt");