Unify reporting resolution errors for empty delegation calls

- Always report "There is no applicable constructor for call without arguments in superclass"
  under `constructor` keyword by replacing default TracingStrategy
- Remove positioning strategy used for reporting non-applicable
  for empty delegation calls

 #KT-6971 Fixed
This commit is contained in:
Denis Zharkov
2015-03-23 10:56:23 +03:00
parent 683bc4709f
commit 7aa2642a2b
11 changed files with 318 additions and 18 deletions
@@ -169,6 +169,7 @@ public interface Errors {
DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL);
DiagnosticFactory0<PsiElement> PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> EXPLICIT_DELEGATION_CALL_REQUIRED = DiagnosticFactory0.create(ERROR);
// Trait-specific
@@ -411,8 +412,7 @@ public interface Errors {
DiagnosticFactory0<JetExpression> NOT_A_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, Collection<? extends ResolvedCall<?>>> OVERLOAD_RESOLUTION_AMBIGUITY = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, Collection<? extends ResolvedCall<?>>> NONE_APPLICABLE =
DiagnosticFactory1.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL_OR_DEFAULT);
DiagnosticFactory1<PsiElement, Collection<? extends ResolvedCall<?>>> NONE_APPLICABLE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, Collection<? extends ResolvedCall<?>>> CANNOT_COMPLETE_RESOLVE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, Collection<? extends ResolvedCall<?>>> UNRESOLVED_REFERENCE_WRONG_RECEIVER = DiagnosticFactory1.create(ERROR);
@@ -62,6 +62,9 @@ public object PositioningStrategies {
element.getNameIdentifier() ?: element.getObjectKeyword()
)
}
is JetConstructorDelegationCall -> {
return SECONDARY_CONSTRUCTOR_DELEGATION_CALL.mark(element)
}
else -> {
return super.mark(element)
}
@@ -422,17 +425,4 @@ public object PositioningStrategies {
return markElement(element.getCalleeExpression() ?: element)
}
}
public val SECONDARY_CONSTRUCTOR_DELEGATION_CALL_OR_DEFAULT: PositioningStrategy<PsiElement> =
object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
val parent = element.getParent()
if (parent is JetConstructorDelegationCall) {
return SECONDARY_CONSTRUCTOR_DELEGATION_CALL.mark(parent)
}
else {
return DEFAULT.mark(element)
}
}
}
}
@@ -397,6 +397,8 @@ public class DefaultErrorMessages {
MAP.put(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, "Primary constructor call expected");
MAP.put(DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR, "Call to super is not allowed in enum constructor");
MAP.put(PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS, "Primary constructor required for data class");
MAP.put(EXPLICIT_DELEGATION_CALL_REQUIRED,
"Explicit 'this' or 'super' call is required. There is no constructor in superclass that can be called without arguments");
MAP.put(INIT_KEYWORD_BEFORE_CLASS_INITIALIZER_EXPECTED, "Expecting 'init' keyword before class initializer");
@@ -188,7 +188,17 @@ public class CallResolver {
@NotNull Collection<ResolutionCandidate<D>> candidates,
@NotNull CallTransformer<D, F> callTransformer
) {
TracingStrategy tracing = TracingStrategyImpl.create(referenceExpression, context.call);
return computeTasksFromCandidatesAndResolvedCall(context, candidates, callTransformer,
TracingStrategyImpl.create(referenceExpression, context.call));
}
@NotNull
private <D extends CallableDescriptor, F extends D> OverloadResolutionResults<F> computeTasksFromCandidatesAndResolvedCall(
@NotNull BasicCallResolutionContext context,
@NotNull Collection<ResolutionCandidate<D>> candidates,
@NotNull CallTransformer<D, F> callTransformer,
@NotNull TracingStrategy tracing
) {
List<ResolutionTask<D, F>> prioritizedTasks =
taskPrioritizer.<D, F>computePrioritizedTasksFromCandidates(context, candidates, tracing);
return doResolveCallOrGetCachedResults(context, prioritizedTasks, callTransformer, tracing);
@@ -313,6 +323,7 @@ public class CallResolver {
return resolveConstructorDelegationCall(
context,
call,
call.getCalleeExpression(),
constructorDescriptor
);
@@ -321,6 +332,7 @@ public class CallResolver {
@NotNull
private OverloadResolutionResults<FunctionDescriptor> resolveConstructorDelegationCall(
@NotNull BasicCallResolutionContext context,
@NotNull JetConstructorDelegationCall call,
@NotNull JetConstructorDelegationReferenceExpression calleeExpression,
@NotNull ConstructorDescriptor calleeConstructor
) {
@@ -364,7 +376,11 @@ public class CallResolver {
knownTypeParametersSubstitutor));
}
return computeTasksFromCandidatesAndResolvedCall(context, calleeExpression, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER);
TracingStrategy tracing = calleeExpression.isEmpty() ?
new TracingStrategyForEmptyConstructorDelegationCall(call, context.call) :
TracingStrategyImpl.create(calleeExpression, context.call);
return computeTasksFromCandidatesAndResolvedCall(context, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing);
}
public OverloadResolutionResults<FunctionDescriptor> resolveCallWithKnownCandidate(
@@ -0,0 +1,146 @@
/*
* 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.resolve.calls.tasks
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE
import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE_WRONG_RECEIVER
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.JetConstructorDelegationCall
import org.jetbrains.kotlin.psi.JetFunctionLiteralArgument
import org.jetbrains.kotlin.psi.JetSecondaryConstructor
import org.jetbrains.kotlin.resolve.BindingContext.CALL
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
import org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.JetType
public class TracingStrategyForEmptyConstructorDelegationCall(
val delegationCall: JetConstructorDelegationCall, call: Call
) : AbstractTracingStrategy(delegationCall.getCalleeExpression()!!, call) {
val calleeExpression = delegationCall.getCalleeExpression()
override fun bindCall(trace: BindingTrace, call: Call) {
trace.record(CALL, call.getCalleeExpression(), call)
}
override fun <D : CallableDescriptor> bindReference(trace: BindingTrace, resolvedCall: ResolvedCall<D>) {
val descriptor = resolvedCall.getCandidateDescriptor()
val storedReference = trace.get(REFERENCE_TARGET, calleeExpression)
if (storedReference == null || !ErrorUtils.isError(descriptor)) {
trace.record(REFERENCE_TARGET, calleeExpression, descriptor)
}
}
override fun <D : CallableDescriptor> bindResolvedCall(trace: BindingTrace, resolvedCall: ResolvedCall<D>) {
trace.record(RESOLVED_CALL, call, resolvedCall)
}
override fun unresolvedReference(trace: BindingTrace) {
trace.report(UNRESOLVED_REFERENCE.on(calleeExpression, calleeExpression))
}
override fun <D : CallableDescriptor> unresolvedReferenceWrongReceiver(trace: BindingTrace, candidates: Collection<ResolvedCall<D>>) {
trace.report(UNRESOLVED_REFERENCE_WRONG_RECEIVER.on(reference, candidates))
}
override fun noValueForParameter(trace: BindingTrace, valueParameter: ValueParameterDescriptor) {
reportError(trace)
}
override fun <D : CallableDescriptor?> ambiguity(trace: BindingTrace, descriptors: MutableCollection<out ResolvedCall<D>>) {
reportError(trace)
}
override fun <D : CallableDescriptor?> noneApplicable(trace: BindingTrace, descriptors: MutableCollection<out ResolvedCall<D>>) {
reportError(trace)
}
override fun invisibleMember(trace: BindingTrace, descriptor: DeclarationDescriptorWithVisibility) {
reportError(trace)
}
private fun reportError(trace: BindingTrace) {
val declaration = delegationCall.getParent() as JetSecondaryConstructor
trace.report(Errors.EXPLICIT_DELEGATION_CALL_REQUIRED.on(declaration.getConstructorKeyword()))
}
// Underlying methods should not be called because such errors are impossible
// when resolving delegation call
override fun <D : CallableDescriptor?> cannotCompleteResolve(trace: BindingTrace, descriptors: MutableCollection<out ResolvedCall<D>>) {
unexpectedError("cannotCompleteResolve")
}
override fun instantiationOfAbstractClass(trace: BindingTrace) {
unexpectedError("instantiationOfAbstractClass")
}
override fun abstractSuperCall(trace: BindingTrace) {
unexpectedError("abstractSuperCall")
}
override fun nestedClassAccessViaInstanceReference(
trace: BindingTrace, classDescriptor: ClassDescriptor, explicitReceiverKind: ExplicitReceiverKind
) {
unexpectedError("nestedClassAccessViaInstanceReference")
}
override fun unsafeCall(trace: BindingTrace, type: JetType, isCallForImplicitInvoke: Boolean) {
unexpectedError("unsafeCall")
}
override fun unnecessarySafeCall(trace: BindingTrace, type: JetType) {
unexpectedError("unnecessarySafeCall")
}
override fun danglingFunctionLiteralArgumentSuspected(
trace: BindingTrace, functionLiteralArguments: MutableList<JetFunctionLiteralArgument>
) {
unexpectedError("danglingFunctionLiteralArgumentSuspected")
}
override fun missingReceiver(trace: BindingTrace, expectedReceiver: ReceiverParameterDescriptor) {
unexpectedError("missingReceiver")
}
override fun wrongReceiverType(trace: BindingTrace, receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue) {
unexpectedError("wrongReceiverType")
}
override fun noReceiverAllowed(trace: BindingTrace) {
unexpectedError("noReceiverAllowed")
}
override fun wrongNumberOfTypeArguments(trace: BindingTrace, expectedTypeArgumentCount: Int) {
unexpectedError("wrongNumberOfTypeArguments")
}
override fun typeInferenceFailed(trace: BindingTrace, data: InferenceErrorData) {
unexpectedError("typeInferenceFailed")
}
private fun unexpectedError(type: String) {
throw AssertionError("Unexpected error type: $type")
}
}
@@ -0,0 +1,42 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
open class B0(x: Int)
class A0 : B0 {
<!EXPLICIT_DELEGATION_CALL_REQUIRED!>constructor<!>()
constructor(x: Int) : super(<!NO_VALUE_FOR_PARAMETER!>)<!>
}
// --------------------------
open class B1 {
constructor(x: Int = 1)
constructor()
}
class A1 : B1 {
<!EXPLICIT_DELEGATION_CALL_REQUIRED!>constructor<!>()
constructor(x: Int) : <!OVERLOAD_RESOLUTION_AMBIGUITY!>super<!>()
}
// --------------------------
open class B2 {
constructor(x: Int)
constructor(x: String)
}
class A2 : B2 {
<!EXPLICIT_DELEGATION_CALL_REQUIRED!>constructor<!>()
constructor(x: Int) : <!NONE_APPLICABLE!>super<!>()
}
// --------------------------
open class B3 {
private constructor()
}
class A3 : B3 {
<!EXPLICIT_DELEGATION_CALL_REQUIRED!>constructor<!>()
constructor(x: Int) : <!INVISIBLE_MEMBER!>super<!>()
}
@@ -0,0 +1,63 @@
package
internal final class A0 : B0 {
public constructor A0()
public constructor A0(/*0*/ x: kotlin.Int)
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 A1 : B1 {
public constructor A1()
public constructor A1(/*0*/ x: kotlin.Int)
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 A2 : B2 {
public constructor A2()
public constructor A2(/*0*/ x: kotlin.Int)
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 A3 : B3 {
public constructor A3()
public constructor A3(/*0*/ x: kotlin.Int)
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 open class B0 {
public constructor B0(/*0*/ x: kotlin.Int)
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 open class B1 {
public constructor B1()
public constructor B1(/*0*/ x: kotlin.Int = ...)
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 open class B2 {
public constructor B2(/*0*/ x: kotlin.Int)
public constructor B2(/*0*/ x: kotlin.String)
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 open class B3 {
private constructor B3()
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
}
@@ -0,0 +1,7 @@
class A {
open inner class Inner
class Nested : Inner {
<!INACCESSIBLE_OUTER_CLASS_EXPRESSION!>constructor()<!>
}
}
@@ -0,0 +1,22 @@
package
internal final class A {
public constructor A()
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 open inner class Inner {
public constructor Inner()
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 Nested : A.Inner {
public constructor Nested()
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
}
}
@@ -6,5 +6,5 @@ open class B(x: Double) {
trait C
class A : B, C {
constructor(): <!NONE_APPLICABLE!>super<!>(' ')
<!NONE_APPLICABLE!>constructor<!>(x: Int)
<!EXPLICIT_DELEGATION_CALL_REQUIRED!>constructor<!>(x: Int)
}
@@ -10647,6 +10647,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("errorsOnEmptyDelegationCall.kt")
public void testErrorsOnEmptyDelegationCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/errorsOnEmptyDelegationCall.kt");
doTest(fileName);
}
@TestMetadata("expectedInitKeywordOnInitializer.kt")
public void testExpectedInitKeywordOnInitializer() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/expectedInitKeywordOnInitializer.kt");
@@ -10719,6 +10725,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("nestedExtendsInner.kt")
public void testNestedExtendsInner() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/nestedExtendsInner.kt");
doTest(fileName);
}
@TestMetadata("noDefaultIfEmptySecondary.kt")
public void testNoDefaultIfEmptySecondary() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/noDefaultIfEmptySecondary.kt");