FE 1.0: implement initial label resolve warning for KT-51433
This commit is contained in:
+6
@@ -33569,6 +33569,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("labelClashes.kt")
|
||||||
|
public void testLabelClashes() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("outstar.kt")
|
@TestMetadata("outstar.kt")
|
||||||
public void testOutstar() throws Exception {
|
public void testOutstar() throws Exception {
|
||||||
|
|||||||
+6
@@ -33569,6 +33569,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("labelClashes.kt")
|
||||||
|
public void testLabelClashes() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("outstar.kt")
|
@TestMetadata("outstar.kt")
|
||||||
public void testOutstar() throws Exception {
|
public void testOutstar() throws Exception {
|
||||||
|
|||||||
+6
@@ -33569,6 +33569,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("labelClashes.kt")
|
||||||
|
public void testLabelClashes() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("outstar.kt")
|
@TestMetadata("outstar.kt")
|
||||||
public void testOutstar() throws Exception {
|
public void testOutstar() throws Exception {
|
||||||
|
|||||||
@@ -1025,6 +1025,7 @@ public interface Errors {
|
|||||||
// Labels
|
// Labels
|
||||||
|
|
||||||
DiagnosticFactory0<KtSimpleNameExpression> LABEL_NAME_CLASH = DiagnosticFactory0.create(WARNING);
|
DiagnosticFactory0<KtSimpleNameExpression> LABEL_NAME_CLASH = DiagnosticFactory0.create(WARNING);
|
||||||
|
DiagnosticFactory2<KtSimpleNameExpression, String, String> LABEL_RESOLVE_WILL_CHANGE = DiagnosticFactory2.create(WARNING);
|
||||||
DiagnosticFactory0<KtSimpleNameExpression> AMBIGUOUS_LABEL = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtSimpleNameExpression> AMBIGUOUS_LABEL = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
DiagnosticFactory0<KtExpressionWithLabel> BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtExpressionWithLabel> BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = DiagnosticFactory0.create(ERROR);
|
||||||
|
|||||||
+2
@@ -193,6 +193,8 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(RETURN_NOT_ALLOWED, "'return' is not allowed here");
|
MAP.put(RETURN_NOT_ALLOWED, "'return' is not allowed here");
|
||||||
MAP.put(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE, "Projections are not allowed for immediate arguments of a supertype");
|
MAP.put(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE, "Projections are not allowed for immediate arguments of a supertype");
|
||||||
MAP.put(LABEL_NAME_CLASH, "There is more than one label with such a name in this scope");
|
MAP.put(LABEL_NAME_CLASH, "There is more than one label with such a name in this scope");
|
||||||
|
MAP.put(LABEL_RESOLVE_WILL_CHANGE, "This label is now resolved to ''{0}'' but soon it will be resolved to the closest ''{1}''. " +
|
||||||
|
"Please consider introducing or changing explicit label name", TO_STRING, TO_STRING);
|
||||||
MAP.put(EXPRESSION_EXPECTED_PACKAGE_FOUND, "Expression expected, but a package name found");
|
MAP.put(EXPRESSION_EXPECTED_PACKAGE_FOUND, "Expression expected, but a package name found");
|
||||||
|
|
||||||
MAP.put(CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, "Cannot import-on-demand from object ''{0}''", NAME);
|
MAP.put(CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, "Cannot import-on-demand from object ''{0}''", NAME);
|
||||||
|
|||||||
@@ -18,12 +18,13 @@ package org.jetbrains.kotlin.types.expressions
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature.ContextReceivers
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.checkReservedYield
|
import org.jetbrains.kotlin.psi.psiUtil.checkReservedYield
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||||
@@ -150,9 +151,15 @@ object LabelResolver {
|
|||||||
labelName: Name
|
labelName: Name
|
||||||
): LabeledReceiverResolutionResult {
|
): LabeledReceiverResolutionResult {
|
||||||
val referenceExpression = expression.instanceReference
|
val referenceExpression = expression.instanceReference
|
||||||
val targetLabel = expression.getTargetLabel() ?: error(expression)
|
val targetLabelExpression = expression.getTargetLabel() ?: error(expression)
|
||||||
|
|
||||||
val declarationsByLabel = context.scope.getDeclarationsByLabel(labelName)
|
val scope = context.scope
|
||||||
|
val declarationsByLabel = scope.getDeclarationsByLabel(labelName)
|
||||||
|
val elementsByLabel = getElementsByLabelName(
|
||||||
|
labelName, targetLabelExpression,
|
||||||
|
classNameLabelsEnabled = expression is KtThisExpression && context.languageVersionSettings.supportsFeature(ContextReceivers)
|
||||||
|
)
|
||||||
|
val trace = context.trace
|
||||||
when (declarationsByLabel.size) {
|
when (declarationsByLabel.size) {
|
||||||
1 -> {
|
1 -> {
|
||||||
val declarationDescriptor = declarationsByLabel.single()
|
val declarationDescriptor = declarationsByLabel.single()
|
||||||
@@ -163,13 +170,20 @@ object LabelResolver {
|
|||||||
else -> throw UnsupportedOperationException("Unsupported descriptor: $declarationDescriptor") // TODO
|
else -> throw UnsupportedOperationException("Unsupported descriptor: $declarationDescriptor") // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
val element = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor)
|
val declarationElement = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor)
|
||||||
?: error("No PSI element for descriptor: $declarationDescriptor")
|
?: error("No PSI element for descriptor: $declarationDescriptor")
|
||||||
context.trace.record(LABEL_TARGET, targetLabel, element)
|
trace.record(LABEL_TARGET, targetLabelExpression, declarationElement)
|
||||||
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
||||||
|
val closestElement = elementsByLabel.firstOrNull()
|
||||||
|
if (closestElement != null && declarationElement in closestElement.parents) {
|
||||||
|
reportLabelResolveWillChange(trace, targetLabelExpression, declarationElement, closestElement)
|
||||||
|
}
|
||||||
|
|
||||||
if (declarationDescriptor is ClassDescriptor) {
|
if (declarationDescriptor is ClassDescriptor) {
|
||||||
if (!DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, targetLabel, declarationDescriptor)) {
|
if (!DescriptorResolver.checkHasOuterClassInstance(
|
||||||
|
scope, trace, targetLabelExpression, declarationDescriptor
|
||||||
|
)
|
||||||
|
) {
|
||||||
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,14 +191,15 @@ object LabelResolver {
|
|||||||
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
|
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
|
||||||
}
|
}
|
||||||
0 -> {
|
0 -> {
|
||||||
val element = resolveNamedLabel(
|
if (elementsByLabel.size > 1) {
|
||||||
labelName, targetLabel, context.trace,
|
trace.report(LABEL_NAME_CLASH.on(targetLabelExpression))
|
||||||
classNameLabelsEnabled = expression is KtThisExpression
|
}
|
||||||
&& context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)
|
val element = elementsByLabel.firstOrNull()?.also {
|
||||||
)
|
trace.record(LABEL_TARGET, targetLabelExpression, it)
|
||||||
val declarationDescriptor = context.trace.bindingContext[DECLARATION_TO_DESCRIPTOR, element]
|
}
|
||||||
|
val declarationDescriptor = trace.bindingContext[DECLARATION_TO_DESCRIPTOR, element]
|
||||||
if (declarationDescriptor is FunctionDescriptor) {
|
if (declarationDescriptor is FunctionDescriptor) {
|
||||||
val labelNameToReceiverMap = context.trace.bindingContext[
|
val labelNameToReceiverMap = trace.bindingContext[
|
||||||
DESCRIPTOR_TO_CONTEXT_RECEIVER_MAP,
|
DESCRIPTOR_TO_CONTEXT_RECEIVER_MAP,
|
||||||
if (declarationDescriptor is PropertyAccessorDescriptor) declarationDescriptor.correspondingProperty else declarationDescriptor
|
if (declarationDescriptor is PropertyAccessorDescriptor) declarationDescriptor.correspondingProperty else declarationDescriptor
|
||||||
]
|
]
|
||||||
@@ -193,23 +208,45 @@ object LabelResolver {
|
|||||||
thisReceivers.isNullOrEmpty() -> declarationDescriptor.extensionReceiverParameter
|
thisReceivers.isNullOrEmpty() -> declarationDescriptor.extensionReceiverParameter
|
||||||
thisReceivers.size == 1 -> thisReceivers.single()
|
thisReceivers.size == 1 -> thisReceivers.single()
|
||||||
else -> {
|
else -> {
|
||||||
BindingContextUtils.reportAmbiguousLabel(context.trace, targetLabel, declarationsByLabel)
|
BindingContextUtils.reportAmbiguousLabel(trace, targetLabelExpression, declarationsByLabel)
|
||||||
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
||||||
}
|
}
|
||||||
}?.also {
|
}?.also {
|
||||||
context.trace.record(LABEL_TARGET, targetLabel, element)
|
trace.record(LABEL_TARGET, targetLabelExpression, element)
|
||||||
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
||||||
}
|
}
|
||||||
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
|
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
|
||||||
} else {
|
} else {
|
||||||
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel, targetLabel))
|
trace.report(UNRESOLVED_REFERENCE.on(targetLabelExpression, targetLabelExpression))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> BindingContextUtils.reportAmbiguousLabel(context.trace, targetLabel, declarationsByLabel)
|
else -> BindingContextUtils.reportAmbiguousLabel(trace, targetLabelExpression, declarationsByLabel)
|
||||||
}
|
}
|
||||||
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun reportLabelResolveWillChange(
|
||||||
|
trace: BindingTrace,
|
||||||
|
target: KtSimpleNameExpression,
|
||||||
|
declarationElement: PsiElement,
|
||||||
|
closestElement: KtElement
|
||||||
|
) {
|
||||||
|
val closestDescription = when (closestElement) {
|
||||||
|
is KtFunctionLiteral -> "anonymous function"
|
||||||
|
is KtNamedFunction -> "function ${closestElement.name} context receiver"
|
||||||
|
is KtPropertyAccessor -> "property ${closestElement.property.name} context receiver"
|
||||||
|
else -> "???"
|
||||||
|
}
|
||||||
|
val declarationDescription = when (declarationElement) {
|
||||||
|
is KtClass -> "class ${declarationElement.name}"
|
||||||
|
is KtNamedFunction -> "function ${declarationElement.name}"
|
||||||
|
is KtProperty -> "property ${declarationElement.name}"
|
||||||
|
is KtNamedDeclaration -> "declaration with name ${declarationElement.name}"
|
||||||
|
else -> "unknown declaration"
|
||||||
|
}
|
||||||
|
trace.report(LABEL_RESOLVE_WILL_CHANGE.on(target, declarationDescription, closestDescription))
|
||||||
|
}
|
||||||
|
|
||||||
class LabeledReceiverResolutionResult private constructor(
|
class LabeledReceiverResolutionResult private constructor(
|
||||||
val code: Code,
|
val code: Code,
|
||||||
private val receiverParameterDescriptor: ReceiverParameterDescriptor?
|
private val receiverParameterDescriptor: ReceiverParameterDescriptor?
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ fun test() {
|
|||||||
|
|
||||||
fun lambda() {
|
fun lambda() {
|
||||||
val funLit = lambda@ fun String.(): String {
|
val funLit = lambda@ fun String.(): String {
|
||||||
return <!NO_THIS!>this@lambda<!>
|
return <!NO_THIS!>this<!LABEL_RESOLVE_WILL_CHANGE!>@lambda<!><!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
fun Int.with() {
|
||||||
|
with("") {
|
||||||
|
<!ARGUMENT_TYPE_MISMATCH!>this@with.<!UNRESOLVED_REFERENCE!>inc<!>()<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Int.bar() {
|
||||||
|
with("") bar@{
|
||||||
|
<!ARGUMENT_TYPE_MISMATCH!>this@bar.<!UNRESOLVED_REFERENCE!>inc<!>()<!>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(f: with.() -> Unit) {}
|
||||||
|
|
||||||
|
class with {
|
||||||
|
fun foo() {
|
||||||
|
with("") {
|
||||||
|
<!ARGUMENT_TYPE_MISMATCH!>this@with.<!UNRESOLVED_REFERENCE!>foo<!>()<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
with("") with@{
|
||||||
|
<!ARGUMENT_TYPE_MISMATCH!>this@with.<!UNRESOLVED_REFERENCE!>foo<!>()<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
with("") other@{
|
||||||
|
this@with.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private typealias Extension = TypedThis
|
||||||
|
|
||||||
|
class TypedThis {
|
||||||
|
fun TypedThis.baz() {
|
||||||
|
this@TypedThis
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Extension.bar() {
|
||||||
|
this@TypedThis
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
fun Int.with() {
|
||||||
|
with("") {
|
||||||
|
this<!LABEL_RESOLVE_WILL_CHANGE("function with; anonymous function")!>@with<!>.inc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Int.bar() {
|
||||||
|
with("") bar@{
|
||||||
|
this<!LABEL_RESOLVE_WILL_CHANGE!>@bar<!>.inc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(f: with.() -> Unit) {}
|
||||||
|
|
||||||
|
class with {
|
||||||
|
fun foo() {
|
||||||
|
with("") {
|
||||||
|
this<!LABEL_RESOLVE_WILL_CHANGE("class with; anonymous function")!>@with<!>.foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
with("") with@{
|
||||||
|
this<!LABEL_RESOLVE_WILL_CHANGE!>@with<!>.foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
with("") other@{
|
||||||
|
this@with.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private typealias Extension = TypedThis
|
||||||
|
|
||||||
|
class TypedThis {
|
||||||
|
fun TypedThis.baz() {
|
||||||
|
this@TypedThis
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Extension.bar() {
|
||||||
|
this@TypedThis
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun foo(/*0*/ f: with.() -> kotlin.Unit): kotlin.Unit
|
||||||
|
public fun kotlin.Int.bar(): kotlin.Unit
|
||||||
|
public fun kotlin.Int.with(): kotlin.Unit
|
||||||
|
|
||||||
|
public final class TypedThis {
|
||||||
|
public constructor TypedThis()
|
||||||
|
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 fun Extension /* = TypedThis */.bar(): kotlin.Unit
|
||||||
|
public final fun TypedThis.baz(): kotlin.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class with {
|
||||||
|
public constructor with()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun foo(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
private typealias Extension = TypedThis
|
||||||
Generated
+6
@@ -33659,6 +33659,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("labelClashes.kt")
|
||||||
|
public void testLabelClashes() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("outstar.kt")
|
@TestMetadata("outstar.kt")
|
||||||
public void testOutstar() throws Exception {
|
public void testOutstar() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user