Resolve control label locally when label name clashes with fun name
#KT-5354 Fixed #KT-15085 Fixed
This commit is contained in:
@@ -102,31 +102,29 @@ object LabelResolver {
|
||||
val labelName = expression.getLabelNameAsName()
|
||||
if (labelElement == null || labelName == null) return null
|
||||
|
||||
val element = resolveNamedLabel(labelName, labelElement, context.trace)
|
||||
if (element != null) return element
|
||||
|
||||
val declarationsByLabel = context.scope.getDeclarationsByLabel(labelName)
|
||||
val size = declarationsByLabel.size
|
||||
|
||||
if (size > 1) {
|
||||
BindingContextUtils.reportAmbiguousLabel(context.trace, labelElement, declarationsByLabel)
|
||||
return null
|
||||
}
|
||||
if (size == 0) {
|
||||
val element = resolveNamedLabel(labelName, labelElement, context.trace)
|
||||
if (element == null) {
|
||||
when (declarationsByLabel.size) {
|
||||
0 -> {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(labelElement, labelElement))
|
||||
return null
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
val declarationDescriptor = declarationsByLabel.iterator().next()
|
||||
if (declarationDescriptor is FunctionDescriptor || declarationDescriptor is ClassDescriptor) {
|
||||
val element = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor)
|
||||
if (element is KtElement) {
|
||||
context.trace.record(LABEL_TARGET, labelElement, element)
|
||||
return element
|
||||
1 -> {
|
||||
val declarationDescriptor = declarationsByLabel.single()
|
||||
if (declarationDescriptor is FunctionDescriptor || declarationDescriptor is ClassDescriptor) {
|
||||
val declarationElement = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor)
|
||||
if (declarationElement is KtElement) {
|
||||
context.trace.record(LABEL_TARGET, labelElement, declarationElement)
|
||||
return declarationElement
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
BindingContextUtils.reportAmbiguousLabel(context.trace, labelElement, declarationsByLabel)
|
||||
return null
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw UnsupportedOperationException(declarationDescriptor.javaClass.toString()) // TODO
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -144,7 +142,7 @@ object LabelResolver {
|
||||
trace.report(LABEL_NAME_CLASH.on(labelExpression))
|
||||
}
|
||||
|
||||
return list.single().also { trace.record(LABEL_TARGET, labelExpression, it) }
|
||||
return list.first().also { trace.record(LABEL_TARGET, labelExpression, it) }
|
||||
}
|
||||
|
||||
fun resolveThisOrSuperLabel(
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
fun test1(): Boolean {
|
||||
test1@ for(i in 1..2) {
|
||||
continue@test1
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun test2(): Boolean {
|
||||
test2@ while (true) {
|
||||
break@test2
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (!test1()) return "fail test1"
|
||||
if (!test2()) return "fail test2"
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+53
@@ -0,0 +1,53 @@
|
||||
fun test1() {
|
||||
test1@ for(i in 1..2) {
|
||||
continue<!LABEL_NAME_CLASH!>@test1<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
test2@ while (true) {
|
||||
break<!LABEL_NAME_CLASH!>@test2<!>
|
||||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
fun Test3() {
|
||||
Test3@ while (true) {
|
||||
break<!LABEL_NAME_CLASH!>@Test3<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test4() {
|
||||
<!NOT_A_LOOP_LABEL!>break@test4<!>
|
||||
}
|
||||
|
||||
class Test5 {
|
||||
fun Test5<!SYNTAX!><!> {
|
||||
return@Test5
|
||||
}
|
||||
}
|
||||
|
||||
class Test6 {
|
||||
fun Test6() {
|
||||
Test6@ while (true) {
|
||||
break<!LABEL_NAME_CLASH!>@Test6<!>
|
||||
}
|
||||
|
||||
Test6@ while (true) {
|
||||
break<!LABEL_NAME_CLASH!>@Test6<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Test7 {
|
||||
fun Test7() {
|
||||
Test8@ while (true) {
|
||||
<!NOT_A_LOOP_LABEL!>break@Test7<!>
|
||||
}
|
||||
|
||||
<!UNREACHABLE_CODE!>Test7@ while (true) {
|
||||
<!NOT_A_LOOP_LABEL!>break<!UNRESOLVED_REFERENCE!>@Test8<!><!>
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
package
|
||||
|
||||
public fun test1(): kotlin.Unit
|
||||
public fun test2(): kotlin.Unit
|
||||
public fun test4(): kotlin.Unit
|
||||
|
||||
public final class Test3 {
|
||||
public constructor Test3()
|
||||
public final fun Test3(): kotlin.Unit
|
||||
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 class Test5 {
|
||||
public constructor Test5()
|
||||
public final fun Test5(): kotlin.Unit
|
||||
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 class Test6 {
|
||||
public constructor Test6()
|
||||
public final fun Test6(): kotlin.Unit
|
||||
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 class Test7 {
|
||||
public constructor Test7()
|
||||
public final fun Test7(): kotlin.Unit
|
||||
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
@@ -10064,6 +10064,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/labels"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("controlLabelClashesWithFuncitonName.kt")
|
||||
public void testControlLabelClashesWithFuncitonName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/controlLabelClashesWithFuncitonName.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("labeledDeclarations.kt")
|
||||
public void testLabeledDeclarations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/labeledDeclarations.kt");
|
||||
|
||||
@@ -4402,6 +4402,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("continueAndBreakLabelWithSameFunctionName.kt")
|
||||
public void testContinueAndBreakLabelWithSameFunctionName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/continueAndBreakLabelWithSameFunctionName.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("emptyIf.kt")
|
||||
public void testEmptyIf() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlStructures/emptyIf.kt");
|
||||
|
||||
@@ -10064,6 +10064,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/labels"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("controlLabelClashesWithFuncitonName.kt")
|
||||
public void testControlLabelClashesWithFuncitonName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/controlLabelClashesWithFuncitonName.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("labeledDeclarations.kt")
|
||||
public void testLabeledDeclarations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/labeledDeclarations.kt");
|
||||
|
||||
@@ -10064,6 +10064,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/labels"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("controlLabelClashesWithFuncitonName.kt")
|
||||
public void testControlLabelClashesWithFuncitonName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/controlLabelClashesWithFuncitonName.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("labeledDeclarations.kt")
|
||||
public void testLabeledDeclarations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/labeledDeclarations.kt");
|
||||
|
||||
@@ -11595,6 +11595,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/labels"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("controlLabelClashesWithFuncitonName.kt")
|
||||
public void testControlLabelClashesWithFuncitonName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/controlLabelClashesWithFuncitonName.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("labeledDeclarations.kt")
|
||||
public void testLabeledDeclarations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/labels/labeledDeclarations.kt");
|
||||
|
||||
Reference in New Issue
Block a user