Destructuring declaration initializer now cannot use extension componentX() on nullable #KT-7794 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-01-25 18:58:14 +03:00
parent 850dc89b38
commit 22c0ddaa48
7 changed files with 91 additions and 24 deletions
@@ -49,7 +49,8 @@ class DestructuringDeclarationResolver(
val componentName = createComponentName(componentIndex + 1)
val expectedType = getExpectedTypeForComponent(context, entry)
val results = fakeCallResolver.resolveFakeCall(context.replaceExpectedType(expectedType), receiver, componentName, entry)
val results = fakeCallResolver.resolveFakeCall(context.replaceExpectedType(expectedType), receiver, componentName,
entry, reportErrorsOn, FakeCallKind.COMPONENT)
var componentType: KotlinType? = null
if (results.isSuccess) {
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
@@ -35,6 +34,12 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.doNothing
import java.util.*
enum class FakeCallKind {
ITERATOR,
COMPONENT,
OTHER
}
class FakeCallResolver(
private val project: Project,
private val callResolver: CallResolver
@@ -44,33 +49,31 @@ class FakeCallResolver(
receiver: ReceiverValue?,
name: Name,
callElement: KtExpression?,
reportErrorsOn: KtExpression? = callElement,
callKind: FakeCallKind = FakeCallKind.OTHER,
vararg argumentTypes: KotlinType
): OverloadResolutionResults<FunctionDescriptor> {
val traceWithFakeArgumentInfo = TemporaryBindingTrace.create(context.trace, "trace to store fake argument for", name)
val fakeArguments = ArrayList<KtExpression>()
for (type in argumentTypes) {
fakeArguments.add(ExpressionTypingUtils.createFakeExpressionOfType(project, traceWithFakeArgumentInfo, "fakeArgument" + fakeArguments.size, type))
fakeArguments.add(ExpressionTypingUtils.createFakeExpressionOfType(project, traceWithFakeArgumentInfo,
"fakeArgument" + fakeArguments.size, type))
}
return makeAndResolveFakeCall(receiver, context.replaceBindingTrace(traceWithFakeArgumentInfo), fakeArguments, name, callElement).second
return makeAndResolveFakeCall(receiver, context.replaceBindingTrace(traceWithFakeArgumentInfo),
fakeArguments, name, callElement, callKind, reportErrorsOn).second
}
@JvmOverloads
fun resolveFakeCall(
context: ExpressionTypingContext,
receiver: ReceiverValue,
name: Name,
callElement: KtExpression
callElement: KtExpression,
reportErrorsOn: KtExpression = callElement,
callKind: FakeCallKind = FakeCallKind.OTHER,
valueArguments: List<KtExpression> = emptyList()
): OverloadResolutionResults<FunctionDescriptor> {
return resolveFakeCall(receiver, context, emptyList(), name, callElement)
}
fun resolveFakeCall(
receiver: ReceiverValue,
context: ExpressionTypingContext,
valueArguments: List<KtExpression>,
name: Name,
callElement: KtExpression
): OverloadResolutionResults<FunctionDescriptor> {
return makeAndResolveFakeCall(receiver, context, valueArguments, name, callElement).second
return makeAndResolveFakeCall(receiver, context, valueArguments, name, callElement, callKind, reportErrorsOn).second
}
fun makeAndResolveFakeCall(
@@ -79,25 +82,33 @@ class FakeCallResolver(
valueArguments: List<KtExpression>,
name: Name,
callElement: KtExpression?,
iteratorCheck: Boolean = false
callKind: FakeCallKind = FakeCallKind.OTHER,
reportErrorsOn: KtExpression? = callElement
): Pair<Call, OverloadResolutionResults<FunctionDescriptor>> {
val fakeTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve fake call for", name)
val fakeBindingTrace = context.replaceBindingTrace(fakeTrace)
var hasUnreportedIteratorError = false
var hasUnreportedError = false
val result = makeAndResolveFakeCallInContext(receiver, fakeBindingTrace, valueArguments, name, callElement) { fake ->
fakeTrace.commit({ slice, diagnostic, key ->
// excluding all entries related to fake expression
// convert all errors on this expression to ITERATOR_MISSING on callElement
val isFakeKey = key == fake
if (iteratorCheck && diagnostic?.severity == Severity.ERROR && isFakeKey) {
hasUnreportedIteratorError = true
if (diagnostic?.severity == Severity.ERROR && isFakeKey) {
hasUnreportedError = true
}
!isFakeKey
}, true)
}
if (hasUnreportedIteratorError && callElement != null) {
context.trace.report(Errors.ITERATOR_MISSING.on(callElement))
if (hasUnreportedError && reportErrorsOn != null) {
when (callKind) {
FakeCallKind.ITERATOR -> context.trace.report(Errors.ITERATOR_MISSING.on(reportErrorsOn))
FakeCallKind.COMPONENT ->
if (receiver != null) {
context.trace.report(Errors.COMPONENT_FUNCTION_MISSING.on(reportErrorsOn, name, receiver.type))
}
FakeCallKind.OTHER -> {}
}
}
return result
}
@@ -67,7 +67,7 @@ public class ForLoopConventionsChecker {
Name iterator = Name.identifier("iterator");
Pair<Call, OverloadResolutionResults<FunctionDescriptor>> calls =
fakeCallResolver.makeAndResolveFakeCall(loopRange, context, Collections.<KtExpression>emptyList(), iterator,
loopRange.getExpression(), true);
loopRangeExpression, FakeCallKind.ITERATOR, loopRangeExpression);
OverloadResolutionResults<FunctionDescriptor> iteratorResolutionResults = calls.getSecond();
if (iteratorResolutionResults.isSuccess()) {
@@ -0,0 +1,21 @@
class Data<T>(val x: T, val y: T)
operator fun <T> Data<T>.component1() = x
operator fun <T> Data<T>.component2() = y
fun foo(): Int {
val d: Data<Int>? = null
// An error must be here
val (x, y) = <!COMPONENT_FUNCTION_MISSING, COMPONENT_FUNCTION_MISSING!>d<!>
return x + y
}
data class NormalData<T>(val x: T, val y: T)
fun bar(): Int {
val d: NormalData<Int>? = null
// An error must be here
val (x, y) = <!COMPONENT_FUNCTION_MISSING, COMPONENT_FUNCTION_MISSING!>d<!>
return <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>x<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>+<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>y<!>
}
@@ -0,0 +1,27 @@
package
public fun bar(): kotlin.Int
public fun foo(): kotlin.Int
public operator fun </*0*/ T> Data<T>.component1(): T
public operator fun </*0*/ T> Data<T>.component2(): T
public final class Data</*0*/ T> {
public constructor Data</*0*/ T>(/*0*/ x: T, /*1*/ y: T)
public final val x: T
public final val y: T
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
}
public final data class NormalData</*0*/ T> {
public constructor NormalData</*0*/ T>(/*0*/ x: T, /*1*/ y: T)
public final val x: T
public final val y: T
public final operator /*synthesized*/ fun component1(): T
public final operator /*synthesized*/ fun component2(): T
public final /*synthesized*/ fun copy(/*0*/ x: T = ..., /*1*/ y: T = ...): NormalData<T>
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
}
@@ -3600,6 +3600,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("extensionComponentsOnNullable.kt")
public void testExtensionComponentsOnNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/extensionComponentsOnNullable.kt");
doTest(fileName);
}
@TestMetadata("implementTraitWhichHasComponent1.kt")
public void testImplementTraitWhichHasComponent1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/implementTraitWhichHasComponent1.kt");
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.tests.di.InjectionKt;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.FakeCallKind;
import java.util.Arrays;
import java.util.HashMap;
@@ -146,7 +147,7 @@ public class ExpectedResolveDataUtil {
DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE);
OverloadResolutionResults<FunctionDescriptor> functions = container.getFakeCallResolver().resolveFakeCall(
context, null, Name.identifier(name), null, parameterTypes);
context, null, Name.identifier(name), null, null, FakeCallKind.OTHER, parameterTypes);
for (ResolvedCall<? extends FunctionDescriptor> resolvedCall : functions.getResultingCalls()) {
List<ValueParameterDescriptor> unsubstitutedValueParameters = resolvedCall.getResultingDescriptor().getValueParameters();