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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("labelClashes.kt")
|
||||
public void testLabelClashes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("outstar.kt")
|
||||
public void testOutstar() throws Exception {
|
||||
|
||||
+6
@@ -33569,6 +33569,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("labelClashes.kt")
|
||||
public void testLabelClashes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("outstar.kt")
|
||||
public void testOutstar() throws Exception {
|
||||
|
||||
+6
@@ -33569,6 +33569,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/kt9985.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("labelClashes.kt")
|
||||
public void testLabelClashes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("outstar.kt")
|
||||
public void testOutstar() throws Exception {
|
||||
|
||||
@@ -1025,6 +1025,7 @@ public interface Errors {
|
||||
// Labels
|
||||
|
||||
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<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(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_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(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 org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ContextReceivers
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.checkReservedYield
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
@@ -150,9 +151,15 @@ object LabelResolver {
|
||||
labelName: Name
|
||||
): LabeledReceiverResolutionResult {
|
||||
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) {
|
||||
1 -> {
|
||||
val declarationDescriptor = declarationsByLabel.single()
|
||||
@@ -163,13 +170,20 @@ object LabelResolver {
|
||||
else -> throw UnsupportedOperationException("Unsupported descriptor: $declarationDescriptor") // TODO
|
||||
}
|
||||
|
||||
val element = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor)
|
||||
val declarationElement = DescriptorToSourceUtils.descriptorToDeclaration(declarationDescriptor)
|
||||
?: error("No PSI element for descriptor: $declarationDescriptor")
|
||||
context.trace.record(LABEL_TARGET, targetLabel, element)
|
||||
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
||||
trace.record(LABEL_TARGET, targetLabelExpression, declarationElement)
|
||||
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 (!DescriptorResolver.checkHasOuterClassInstance(context.scope, context.trace, targetLabel, declarationDescriptor)) {
|
||||
if (!DescriptorResolver.checkHasOuterClassInstance(
|
||||
scope, trace, targetLabelExpression, declarationDescriptor
|
||||
)
|
||||
) {
|
||||
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
||||
}
|
||||
}
|
||||
@@ -177,14 +191,15 @@ object LabelResolver {
|
||||
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
|
||||
}
|
||||
0 -> {
|
||||
val element = resolveNamedLabel(
|
||||
labelName, targetLabel, context.trace,
|
||||
classNameLabelsEnabled = expression is KtThisExpression
|
||||
&& context.languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)
|
||||
)
|
||||
val declarationDescriptor = context.trace.bindingContext[DECLARATION_TO_DESCRIPTOR, element]
|
||||
if (elementsByLabel.size > 1) {
|
||||
trace.report(LABEL_NAME_CLASH.on(targetLabelExpression))
|
||||
}
|
||||
val element = elementsByLabel.firstOrNull()?.also {
|
||||
trace.record(LABEL_TARGET, targetLabelExpression, it)
|
||||
}
|
||||
val declarationDescriptor = trace.bindingContext[DECLARATION_TO_DESCRIPTOR, element]
|
||||
if (declarationDescriptor is FunctionDescriptor) {
|
||||
val labelNameToReceiverMap = context.trace.bindingContext[
|
||||
val labelNameToReceiverMap = trace.bindingContext[
|
||||
DESCRIPTOR_TO_CONTEXT_RECEIVER_MAP,
|
||||
if (declarationDescriptor is PropertyAccessorDescriptor) declarationDescriptor.correspondingProperty else declarationDescriptor
|
||||
]
|
||||
@@ -193,23 +208,45 @@ object LabelResolver {
|
||||
thisReceivers.isNullOrEmpty() -> declarationDescriptor.extensionReceiverParameter
|
||||
thisReceivers.size == 1 -> thisReceivers.single()
|
||||
else -> {
|
||||
BindingContextUtils.reportAmbiguousLabel(context.trace, targetLabel, declarationsByLabel)
|
||||
BindingContextUtils.reportAmbiguousLabel(trace, targetLabelExpression, declarationsByLabel)
|
||||
return LabeledReceiverResolutionResult.labelResolutionFailed()
|
||||
}
|
||||
}?.also {
|
||||
context.trace.record(LABEL_TARGET, targetLabel, element)
|
||||
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
||||
trace.record(LABEL_TARGET, targetLabelExpression, element)
|
||||
trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
|
||||
}
|
||||
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
|
||||
} 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()
|
||||
}
|
||||
|
||||
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(
|
||||
val code: Code,
|
||||
private val receiverParameterDescriptor: ReceiverParameterDescriptor?
|
||||
|
||||
@@ -12,6 +12,6 @@ fun test() {
|
||||
|
||||
fun lambda() {
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("labelClashes.kt")
|
||||
public void testLabelClashes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/labelClashes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("outstar.kt")
|
||||
public void testOutstar() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user