FE 1.0: implement initial label resolve warning for KT-51433

This commit is contained in:
Mikhail Glukhikh
2022-02-22 11:11:45 +03:00
committed by Space
parent 31b234a261
commit b5e2c492c6
11 changed files with 191 additions and 22 deletions
@@ -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 {
@@ -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 {
@@ -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);
@@ -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
@@ -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 {