Introduce FirForLoopChecker
This commit is contained in:
+206
@@ -0,0 +1,206 @@
|
||||
FILE: forLoopChecker.kt
|
||||
public final class NotRange1 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange1| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public abstract class NotRange2 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange2| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
public abstract class ImproperIterator1 : R|kotlin/Any| {
|
||||
public constructor(): R|ImproperIterator1| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun hasNext(): R|kotlin/Boolean|
|
||||
|
||||
}
|
||||
public abstract class NotRange3 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange3| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|ImproperIterator1|
|
||||
|
||||
}
|
||||
public abstract class ImproperIterator2 : R|kotlin/Any| {
|
||||
public constructor(): R|ImproperIterator2| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun next(): R|kotlin/Boolean|
|
||||
|
||||
}
|
||||
public abstract class NotRange4 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange4| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|ImproperIterator2|
|
||||
|
||||
}
|
||||
public abstract class ImproperIterator3 : R|kotlin/Any| {
|
||||
public constructor(): R|ImproperIterator3| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun hasNext(): R|kotlin/Int|
|
||||
|
||||
public abstract operator fun next(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
public abstract class NotRange5 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange5| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|ImproperIterator3|
|
||||
|
||||
}
|
||||
public abstract class AmbiguousHasNextIterator : R|kotlin/Any| {
|
||||
public constructor(): R|AmbiguousHasNextIterator| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun hasNext(): R|kotlin/Boolean|
|
||||
|
||||
public final val hasNext: R|kotlin/Boolean|
|
||||
public get(): R|kotlin/Boolean| {
|
||||
^ Boolean(false)
|
||||
}
|
||||
|
||||
public abstract operator fun next(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
public abstract class NotRange6 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange6| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|AmbiguousHasNextIterator|
|
||||
|
||||
}
|
||||
public abstract class ImproperIterator4 : R|kotlin/Any| {
|
||||
public constructor(): R|ImproperIterator4| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val hasNext: R|kotlin/Int|
|
||||
public get(): R|kotlin/Int| {
|
||||
^ Int(1)
|
||||
}
|
||||
|
||||
public abstract operator fun next(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
public abstract class NotRange7 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange7| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|ImproperIterator3|
|
||||
|
||||
}
|
||||
public abstract class GoodIterator : R|kotlin/Any| {
|
||||
public constructor(): R|GoodIterator| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun hasNext(): R|kotlin/Boolean|
|
||||
|
||||
public abstract operator fun next(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
public abstract class Range0 : R|kotlin/Any| {
|
||||
public constructor(): R|Range0| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|GoodIterator|
|
||||
|
||||
}
|
||||
public abstract class Range1 : R|kotlin/Any| {
|
||||
public constructor(): R|Range1| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|kotlin/collections/Iterator<kotlin/Int>|
|
||||
|
||||
}
|
||||
public abstract class ImproperIterator5 : R|kotlin/Any| {
|
||||
public constructor(): R|ImproperIterator5| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract val R|kotlin/String|.hasNext: R|kotlin/Boolean|
|
||||
public get(): R|kotlin/Boolean|
|
||||
|
||||
public abstract operator fun next(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
public abstract class NotRange8 : R|kotlin/Any| {
|
||||
public constructor(): R|NotRange8| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public abstract operator fun iterator(): R|ImproperIterator5|
|
||||
|
||||
}
|
||||
public final fun test(notRange1: R|NotRange1|, notRange2: R|NotRange2|, notRange3: R|NotRange3|, notRange4: R|NotRange4|, notRange5: R|NotRange5|, notRange6: R|NotRange6|, notRange7: R|NotRange7|, notRange8: R|NotRange8|, range0: R|Range0|, range1: R|Range1|): R|kotlin/Unit| {
|
||||
lval <iterator>: R|ERROR CLASS: Unresolved name: iterator| = R|<local>/notRange1|.<Unresolved name: iterator>#()
|
||||
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
|
||||
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
}
|
||||
|
||||
lval <iterator>: R|kotlin/Unit| = R|<local>/notRange2|.R|/NotRange2.iterator|()
|
||||
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
|
||||
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
}
|
||||
|
||||
lval <iterator>: R|ImproperIterator1| = R|<local>/notRange3|.R|/NotRange3.iterator|()
|
||||
while(R|<local>/<iterator>|.R|/ImproperIterator1.hasNext|()) {
|
||||
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
}
|
||||
|
||||
lval <iterator>: R|ImproperIterator2| = R|<local>/notRange4|.R|/NotRange4.iterator|()
|
||||
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
|
||||
lval i: R|kotlin/Boolean| = R|<local>/<iterator>|.R|/ImproperIterator2.next|()
|
||||
}
|
||||
|
||||
lval <iterator>: R|ImproperIterator3| = R|<local>/notRange5|.R|/NotRange5.iterator|()
|
||||
while(R|<local>/<iterator>|.R|/ImproperIterator3.hasNext|()) {
|
||||
lval i: R|kotlin/Int| = R|<local>/<iterator>|.R|/ImproperIterator3.next|()
|
||||
}
|
||||
|
||||
lval <iterator>: R|AmbiguousHasNextIterator| = R|<local>/notRange6|.R|/NotRange6.iterator|()
|
||||
while(R|<local>/<iterator>|.R|/AmbiguousHasNextIterator.hasNext|()) {
|
||||
lval i: R|kotlin/Int| = R|<local>/<iterator>|.R|/AmbiguousHasNextIterator.next|()
|
||||
}
|
||||
|
||||
lval <iterator>: R|ImproperIterator3| = R|<local>/notRange7|.R|/NotRange7.iterator|()
|
||||
while(R|<local>/<iterator>|.R|/ImproperIterator3.hasNext|()) {
|
||||
lval i: R|kotlin/Int| = R|<local>/<iterator>|.R|/ImproperIterator3.next|()
|
||||
}
|
||||
|
||||
lval <iterator>: R|ImproperIterator5| = R|<local>/notRange8|.R|/NotRange8.iterator|()
|
||||
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
|
||||
lval i: R|kotlin/Int| = R|<local>/<iterator>|.R|/ImproperIterator5.next|()
|
||||
}
|
||||
|
||||
lval <iterator>: R|GoodIterator| = R|<local>/range0|.R|/Range0.iterator|()
|
||||
while(R|<local>/<iterator>|.R|/GoodIterator.hasNext|()) {
|
||||
lval i: R|kotlin/Int| = R|<local>/<iterator>|.R|/GoodIterator.next|()
|
||||
}
|
||||
|
||||
lval <iterator>: R|kotlin/collections/Iterator<kotlin/Int>| = R|<local>/range1|.R|/Range1.iterator|()
|
||||
while(R|<local>/<iterator>|.R|kotlin/collections/Iterator.hasNext|()) {
|
||||
lval i: R|kotlin/Int| = R|<local>/<iterator>|.R|SubstitutionOverride<kotlin/collections/Iterator.next: R|kotlin/Int|>|()
|
||||
}
|
||||
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
import java.util.*;
|
||||
|
||||
class NotRange1() {
|
||||
|
||||
}
|
||||
|
||||
abstract class NotRange2() {
|
||||
abstract operator fun iterator() : Unit
|
||||
}
|
||||
|
||||
abstract class ImproperIterator1 {
|
||||
abstract operator fun hasNext() : Boolean
|
||||
}
|
||||
|
||||
abstract class NotRange3() {
|
||||
abstract operator fun iterator() : ImproperIterator1
|
||||
}
|
||||
|
||||
abstract class ImproperIterator2 {
|
||||
abstract operator fun next() : Boolean
|
||||
}
|
||||
|
||||
abstract class NotRange4() {
|
||||
abstract operator fun iterator() : ImproperIterator2
|
||||
}
|
||||
|
||||
abstract class ImproperIterator3 {
|
||||
abstract operator fun hasNext() : Int
|
||||
abstract operator fun next() : Int
|
||||
}
|
||||
|
||||
abstract class NotRange5() {
|
||||
abstract operator fun iterator() : ImproperIterator3
|
||||
}
|
||||
|
||||
abstract class AmbiguousHasNextIterator {
|
||||
abstract operator fun hasNext() : Boolean
|
||||
val hasNext : Boolean get() = false
|
||||
abstract operator fun next() : Int
|
||||
}
|
||||
|
||||
abstract class NotRange6() {
|
||||
abstract operator fun iterator() : AmbiguousHasNextIterator
|
||||
}
|
||||
|
||||
abstract class ImproperIterator4 {
|
||||
val hasNext : Int get() = 1
|
||||
abstract operator fun next() : Int
|
||||
}
|
||||
|
||||
abstract class NotRange7() {
|
||||
abstract operator fun iterator() : ImproperIterator3
|
||||
}
|
||||
|
||||
abstract class GoodIterator {
|
||||
abstract operator fun hasNext() : Boolean
|
||||
abstract operator fun next() : Int
|
||||
}
|
||||
|
||||
abstract class Range0() {
|
||||
abstract operator fun iterator() : GoodIterator
|
||||
}
|
||||
|
||||
abstract class Range1() {
|
||||
abstract operator fun iterator() : Iterator<Int>
|
||||
}
|
||||
|
||||
abstract class ImproperIterator5 {
|
||||
abstract val String.hasNext : Boolean
|
||||
abstract operator fun next() : Int
|
||||
}
|
||||
|
||||
abstract class NotRange8() {
|
||||
abstract operator fun iterator() : ImproperIterator5
|
||||
}
|
||||
|
||||
|
||||
fun test(notRange1: NotRange1, notRange2: NotRange2, notRange3: NotRange3, notRange4: NotRange4, notRange5: NotRange5, notRange6: NotRange6, notRange7: NotRange7, notRange8: NotRange8, range0: Range0, range1: Range1) {
|
||||
for (i in <!ITERATOR_MISSING!>notRange1<!>);
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange2<!>);
|
||||
for (i in <!NEXT_MISSING!>notRange3<!>);
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange4<!>);
|
||||
for (i in notRange5);
|
||||
for (i in notRange6);
|
||||
for (i in notRange7);
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange8<!>);
|
||||
for (i in range0);
|
||||
for (i in range1);
|
||||
}
|
||||
+6
@@ -4827,6 +4827,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forLoopChecker.kt")
|
||||
public void testForLoopChecker() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+6
@@ -4898,6 +4898,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("forLoopChecker.kt")
|
||||
public void testForLoopChecker() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/forLoopChecker.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+19
@@ -256,6 +256,15 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val ASSIGN_OPERATOR_AMBIGUITY by error<PsiElement> {
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
val ITERATOR_AMBIGUITY by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
val HAS_NEXT_FUNCTION_AMBIGUITY by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
val NEXT_AMBIGUITY by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPES_AND_TYPE_PARAMETERS by object : DiagnosticGroup("Types & type parameters") {
|
||||
@@ -612,6 +621,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<String>("operator")
|
||||
parameter<FirExpression>("rhs")
|
||||
}
|
||||
val ITERATOR_ON_NULLABLE by error<FirSourceElement, KtExpression>()
|
||||
val UNNECESSARY_SAFE_CALL by warning<PsiElement>(PositioningStrategy.SAFE_ACCESS) {
|
||||
parameter<ConeKotlinType>("receiverType")
|
||||
}
|
||||
@@ -648,6 +658,15 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val CONVENTIONS by object : DiagnosticGroup("Conventions") {
|
||||
val NO_GET_METHOD by error<KtArrayAccessExpression>(PositioningStrategy.ARRAY_ACCESS)
|
||||
val NO_SET_METHOD by error<KtArrayAccessExpression>(PositioningStrategy.ARRAY_ACCESS)
|
||||
val ITERATOR_MISSING by error<FirSourceElement, KtExpression>()
|
||||
val HAS_NEXT_MISSING by error<FirSourceElement, KtExpression>()
|
||||
val NEXT_MISSING by error<FirSourceElement, KtExpression>()
|
||||
val HAS_NEXT_FUNCTION_NONE_APPLICABLE by error<FirSourceElement, KtExpression> {
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
val NEXT_NONE_APPLICABLE by error<FirSourceElement, KtExpression> {
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
|
||||
|
||||
@@ -208,6 +208,9 @@ object FirErrors {
|
||||
// Ambiguity
|
||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val ASSIGN_OPERATOR_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>()
|
||||
val ITERATOR_AMBIGUITY by error1<FirSourceElement, PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val HAS_NEXT_FUNCTION_AMBIGUITY by error1<FirSourceElement, PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val NEXT_AMBIGUITY by error1<FirSourceElement, PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
// Types & type parameters
|
||||
val TYPE_MISMATCH by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
|
||||
@@ -362,6 +365,7 @@ object FirErrors {
|
||||
val UNSAFE_IMPLICIT_INVOKE_CALL by error1<PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val UNSAFE_INFIX_CALL by error3<KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val UNSAFE_OPERATOR_CALL by error3<KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val ITERATOR_ON_NULLABLE by error0<FirSourceElement, KtExpression>()
|
||||
val UNNECESSARY_SAFE_CALL by warning1<PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.SAFE_ACCESS)
|
||||
val UNEXPECTED_SAFE_CALL by error0<PsiElement>(SourceElementPositioningStrategies.SAFE_ACCESS)
|
||||
val UNNECESSARY_NOT_NULL_ASSERTION by warning1<KtExpression, ConeKotlinType>(SourceElementPositioningStrategies.OPERATOR)
|
||||
@@ -382,6 +386,11 @@ object FirErrors {
|
||||
// Conventions
|
||||
val NO_GET_METHOD by error0<KtArrayAccessExpression>(SourceElementPositioningStrategies.ARRAY_ACCESS)
|
||||
val NO_SET_METHOD by error0<KtArrayAccessExpression>(SourceElementPositioningStrategies.ARRAY_ACCESS)
|
||||
val ITERATOR_MISSING by error0<FirSourceElement, KtExpression>()
|
||||
val HAS_NEXT_MISSING by error0<FirSourceElement, KtExpression>()
|
||||
val NEXT_MISSING by error0<FirSourceElement, KtExpression>()
|
||||
val HAS_NEXT_FUNCTION_NONE_APPLICABLE by error1<FirSourceElement, KtExpression, Collection<AbstractFirBasedSymbol<*>>>()
|
||||
val NEXT_NONE_APPLICABLE by error1<FirSourceElement, KtExpression, Collection<AbstractFirBasedSymbol<*>>>()
|
||||
|
||||
// Type alias
|
||||
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_NONE_APPLICABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_MISSING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_MISSING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_ON_NULLABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_MISSING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_NONE_APPLICABLE
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.InapplicableWrongReceiver
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
|
||||
object FirForLoopChecker : FirBlockChecker() {
|
||||
override fun check(expression: FirBlock, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val statements = expression.statements
|
||||
for ((iteratorDeclaration, whileLoop) in statements.windowed(2)) {
|
||||
if (iteratorDeclaration !is FirProperty) continue
|
||||
if (whileLoop !is FirWhileLoop) continue
|
||||
if (iteratorDeclaration.source?.kind != FirFakeSourceElementKind.DesugaredForLoop) continue
|
||||
val iteratorCall = iteratorDeclaration.initializer as FirFunctionCall
|
||||
val source = iteratorCall.explicitReceiver?.source ?: iteratorCall.source
|
||||
if (checkSpecialFunctionCall(
|
||||
iteratorCall,
|
||||
reporter,
|
||||
source,
|
||||
context,
|
||||
ITERATOR_AMBIGUITY,
|
||||
ITERATOR_MISSING,
|
||||
unsafeCallFactory = ITERATOR_ON_NULLABLE
|
||||
)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
val hasNextCall = whileLoop.condition as FirFunctionCall
|
||||
if (checkSpecialFunctionCall(
|
||||
hasNextCall,
|
||||
reporter,
|
||||
source,
|
||||
context,
|
||||
HAS_NEXT_FUNCTION_AMBIGUITY,
|
||||
HAS_NEXT_MISSING,
|
||||
noneApplicableFactory = HAS_NEXT_FUNCTION_NONE_APPLICABLE
|
||||
)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
val elementDeclaration = whileLoop.block.statements.firstOrNull() as? FirProperty ?: continue
|
||||
if (elementDeclaration.initializer?.source?.kind != FirFakeSourceElementKind.DesugaredForLoop) continue
|
||||
val nextCall = elementDeclaration.initializer as FirFunctionCall
|
||||
checkSpecialFunctionCall(
|
||||
nextCall,
|
||||
reporter,
|
||||
source,
|
||||
context,
|
||||
NEXT_AMBIGUITY,
|
||||
NEXT_MISSING,
|
||||
noneApplicableFactory = NEXT_NONE_APPLICABLE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkSpecialFunctionCall(
|
||||
call: FirFunctionCall,
|
||||
reporter: DiagnosticReporter,
|
||||
reportSource: FirSourceElement?,
|
||||
context: CheckerContext,
|
||||
ambiguityFactory: FirDiagnosticFactory1<FirSourceElement, PsiElement, Collection<AbstractFirBasedSymbol<*>>>,
|
||||
missingFactory: FirDiagnosticFactory0<FirSourceElement, KtExpression>,
|
||||
noneApplicableFactory: FirDiagnosticFactory1<FirSourceElement, KtExpression, Collection<AbstractFirBasedSymbol<*>>>? = null,
|
||||
unsafeCallFactory: FirDiagnosticFactory0<FirSourceElement, KtExpression>? = null,
|
||||
): Boolean {
|
||||
val calleeReference = call.calleeReference
|
||||
if (calleeReference is FirErrorNamedReference) {
|
||||
when (val diagnostic = calleeReference.diagnostic) {
|
||||
is ConeAmbiguityError -> if (diagnostic.applicability.isSuccess) {
|
||||
reporter.reportOn(reportSource, ambiguityFactory, diagnostic.candidates, context)
|
||||
} else if (noneApplicableFactory != null) {
|
||||
reporter.reportOn(reportSource, noneApplicableFactory, diagnostic.candidates, context)
|
||||
}
|
||||
is ConeUnresolvedNameError -> {
|
||||
reporter.reportOn(reportSource, missingFactory, context)
|
||||
}
|
||||
is ConeInapplicableCandidateError -> {
|
||||
if (unsafeCallFactory != null || noneApplicableFactory != null) {
|
||||
diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.forEach {
|
||||
if (it is InapplicableWrongReceiver) {
|
||||
if (unsafeCallFactory != null) {
|
||||
reporter.reportOn(reportSource, unsafeCallFactory, context)
|
||||
} else {
|
||||
reporter.reportOn(reportSource, noneApplicableFactory!!, listOf(diagnostic.candidate.symbol), context)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -16,8 +16,6 @@ import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
||||
@@ -92,7 +90,8 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
|
||||
if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) {
|
||||
return
|
||||
}
|
||||
if (source.kind == FirFakeSourceElementKind.ImplicitConstructor) {
|
||||
if (source.kind == FirFakeSourceElementKind.ImplicitConstructor || source.kind == FirFakeSourceElementKind.DesugaredForLoop) {
|
||||
// See FirForLoopChecker
|
||||
return
|
||||
}
|
||||
for (coneDiagnostic in diagnostic.toFirDiagnostics(source, qualifiedAccessSource)) {
|
||||
|
||||
+6
@@ -110,6 +110,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE_SUBCLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HIDDEN
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
|
||||
@@ -134,6 +135,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INSTANCE_ACCESS_B
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SUPERCLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_IF_AS_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_ANNOTATION_CLASS_ERROR
|
||||
@@ -152,6 +154,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_ARGUMENTS_N
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_PARAMETER_NOT_FOUND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_FINAL_MEMBER_IN_FINAL_CLASS
|
||||
@@ -439,6 +442,9 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
// Ambiguity
|
||||
map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS)
|
||||
map.put(ASSIGN_OPERATOR_AMBIGUITY, "Ambiguity between assign operator candidates: {0}", SYMBOLS)
|
||||
map.put(ITERATOR_AMBIGUITY, "Method ''iterator()'' is ambiguous for this expression: {0}", SYMBOLS)
|
||||
map.put(HAS_NEXT_FUNCTION_AMBIGUITY, "Method ''hasNext()'' is ambiguous for this expression: {0}", SYMBOLS)
|
||||
map.put(NEXT_AMBIGUITY, "Method ''next()'' is ambiguous for this expression: {0}", SYMBOLS)
|
||||
|
||||
// Types & type parameters
|
||||
map.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING)
|
||||
|
||||
+5
@@ -60,4 +60,9 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirReturnAllowedChecker,
|
||||
FirFunctionReturnTypeMismatchChecker
|
||||
)
|
||||
|
||||
override val blockCheckers: Set<FirBlockChecker>
|
||||
get() = setOf(
|
||||
FirForLoopChecker
|
||||
)
|
||||
}
|
||||
|
||||
+21
-7
@@ -944,13 +944,19 @@ class ExpressionsConverter(
|
||||
}
|
||||
}
|
||||
|
||||
val fakeSource = forLoop.toFirSourceElement(FirFakeSourceElementKind.DesugaredForLoop)
|
||||
val target: FirLoopTarget
|
||||
// NB: FirForLoopChecker relies on this block existence and structure
|
||||
return buildBlock {
|
||||
source = forLoop.toFirSourceElement()
|
||||
source = fakeSource
|
||||
val iteratorVal = generateTemporaryVariable(
|
||||
this@ExpressionsConverter.baseSession, null, Name.special("<iterator>"),
|
||||
this@ExpressionsConverter.baseSession, fakeSource, ITERATOR_NAME,
|
||||
buildFunctionCall {
|
||||
calleeReference = buildSimpleNamedReference { name = Name.identifier("iterator") }
|
||||
source = fakeSource
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
source = fakeSource
|
||||
name = OperatorNameConventions.ITERATOR
|
||||
}
|
||||
explicitReceiver = rangeExpression
|
||||
}
|
||||
)
|
||||
@@ -958,8 +964,12 @@ class ExpressionsConverter(
|
||||
statements += FirWhileLoopBuilder().apply {
|
||||
source = forLoop.toFirSourceElement()
|
||||
condition = buildFunctionCall {
|
||||
calleeReference = buildSimpleNamedReference { name = Name.identifier("hasNext") }
|
||||
explicitReceiver = generateResolvedAccessExpression(null, iteratorVal)
|
||||
source = fakeSource
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
source = fakeSource
|
||||
name = OperatorNameConventions.HAS_NEXT
|
||||
}
|
||||
explicitReceiver = generateResolvedAccessExpression(fakeSource, iteratorVal)
|
||||
}
|
||||
// break/continue in the for loop condition will refer to an outer loop if any.
|
||||
// So, prepare the loop target after building the condition.
|
||||
@@ -975,8 +985,12 @@ class ExpressionsConverter(
|
||||
this@ExpressionsConverter.baseSession, null,
|
||||
if (multiDeclaration != null) DESTRUCTURING_NAME else parameter!!.firValueParameter.name,
|
||||
buildFunctionCall {
|
||||
calleeReference = buildSimpleNamedReference { name = Name.identifier("next") }
|
||||
explicitReceiver = generateResolvedAccessExpression(null, iteratorVal)
|
||||
source = fakeSource
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
source = fakeSource
|
||||
name = OperatorNameConventions.NEXT
|
||||
}
|
||||
explicitReceiver = generateResolvedAccessExpression(fakeSource, iteratorVal)
|
||||
},
|
||||
parameter!!.firValueParameter.returnTypeRef
|
||||
)
|
||||
|
||||
@@ -1708,16 +1708,17 @@ open class RawFirBuilder(
|
||||
val ktParameter = expression.loopParameter
|
||||
val fakeSource = expression.toFirPsiSourceElement(FirFakeSourceElementKind.DesugaredForLoop)
|
||||
val target: FirLoopTarget
|
||||
// NB: FirForLoopChecker relies on this block existence and structure
|
||||
return buildBlock {
|
||||
source = fakeSource
|
||||
val rangeSource = expression.loopRange?.toFirSourceElement(FirFakeSourceElementKind.DesugaredForLoop)
|
||||
val iteratorVal = generateTemporaryVariable(
|
||||
baseSession, rangeSource, Name.special("<iterator>"),
|
||||
baseSession, rangeSource, ITERATOR_NAME,
|
||||
buildFunctionCall {
|
||||
source = fakeSource
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
source = fakeSource
|
||||
name = Name.identifier("iterator")
|
||||
name = OperatorNameConventions.ITERATOR
|
||||
}
|
||||
explicitReceiver = rangeExpression
|
||||
},
|
||||
@@ -1729,7 +1730,7 @@ open class RawFirBuilder(
|
||||
source = fakeSource
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
source = fakeSource
|
||||
name = Name.identifier("hasNext")
|
||||
name = OperatorNameConventions.HAS_NEXT
|
||||
}
|
||||
explicitReceiver = generateResolvedAccessExpression(fakeSource, iteratorVal)
|
||||
}
|
||||
@@ -1755,7 +1756,7 @@ open class RawFirBuilder(
|
||||
source = fakeSource
|
||||
calleeReference = buildSimpleNamedReference {
|
||||
source = fakeSource
|
||||
name = Name.identifier("next")
|
||||
name = OperatorNameConventions.NEXT
|
||||
}
|
||||
explicitReceiver = generateResolvedAccessExpression(fakeSource, iteratorVal)
|
||||
},
|
||||
|
||||
+2
@@ -1207,5 +1207,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
val ANONYMOUS_OBJECT_NAME = Name.special("<anonymous>")
|
||||
|
||||
val DESTRUCTURING_NAME = Name.special("<destruct>")
|
||||
|
||||
val ITERATOR_NAME = Name.special("<iterator>")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,14 +78,14 @@ abstract class NotRange8() {
|
||||
|
||||
|
||||
fun test(notRange1: NotRange1, notRange2: NotRange2, notRange3: NotRange3, notRange4: NotRange4, notRange5: NotRange5, notRange6: NotRange6, notRange7: NotRange7, notRange8: NotRange8, range0: Range0, range1: Range1) {
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (i in notRange1)<!>;
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (i in notRange2)<!>;
|
||||
<!UNRESOLVED_REFERENCE!>for (i in notRange3)<!>;
|
||||
<!UNRESOLVED_REFERENCE!>for (i in notRange4)<!>;
|
||||
for (i in <!ITERATOR_MISSING!>notRange1<!>);
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange2<!>);
|
||||
for (i in <!NEXT_MISSING!>notRange3<!>);
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange4<!>);
|
||||
for (i in notRange5);
|
||||
for (i in notRange6);
|
||||
for (i in notRange7);
|
||||
<!UNRESOLVED_REFERENCE!>for (i in notRange8)<!>;
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange8<!>);
|
||||
for (i in range0);
|
||||
for (i in range1);
|
||||
|
||||
|
||||
+2
-2
@@ -22,11 +22,11 @@ fun testUnresolved() {
|
||||
is String -> <!UNRESOLVED_REFERENCE!>a<!>
|
||||
}
|
||||
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (j in <!UNRESOLVED_REFERENCE!>collection<!>) {
|
||||
for (j in <!ITERATOR_MISSING, UNRESOLVED_REFERENCE!>collection<!>) {
|
||||
var i: Int = j
|
||||
i += 1
|
||||
foo1(j)
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun foo1(i: Int) {}
|
||||
|
||||
Vendored
-22
@@ -1,22 +0,0 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// See also KT-7428
|
||||
class Container<K>(val k: K)
|
||||
// iterator() must be an extension, otherwise code will not compile
|
||||
operator fun <K> Container<K>.iterator(): Iterator<K> = null!!
|
||||
|
||||
fun test() {
|
||||
val container: Container<String>? = null
|
||||
// Error
|
||||
container<!UNSAFE_CALL!>.<!>iterator()
|
||||
// for extension iterator, this code compiles, but should not
|
||||
<!UNSAFE_CALL!>for (s in container) {}<!>
|
||||
}
|
||||
class OtherContainer<K>(val k: K) {
|
||||
operator fun iterator(): Iterator<K> = null!!
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
val other: OtherContainer<String>? = null
|
||||
// Error
|
||||
<!UNSAFE_CALL!>for (s in other) {}<!>
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !WITH_NEW_INFERENCE
|
||||
// See also KT-7428
|
||||
class Container<K>(val k: K)
|
||||
|
||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
||||
|
||||
fun foo1() = <!EXPRESSION_EXPECTED!>while (b()) {}<!>
|
||||
|
||||
fun foo2() = <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (i in 10) {}<!>
|
||||
fun foo2() = for (i in <!ITERATOR_MISSING!>10<!>) {}
|
||||
|
||||
fun foo3() = when (b()) {
|
||||
true -> 1
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ class It {
|
||||
}
|
||||
|
||||
fun test(c: Coll?) {
|
||||
<!UNSAFE_CALL!>for (x in c) {}<!>
|
||||
for (x in <!ITERATOR_ON_NULLABLE!>c<!>) {}
|
||||
|
||||
if (c != null) {
|
||||
for(x in c) {}
|
||||
|
||||
+1
-1
@@ -8,5 +8,5 @@ class It {
|
||||
}
|
||||
|
||||
fun test() {
|
||||
<!UNSAFE_CALL, UNSAFE_CALL!>for (x in Coll()) {}<!>
|
||||
for (x in <!HAS_NEXT_FUNCTION_NONE_APPLICABLE!>Coll()<!>) {}
|
||||
}
|
||||
+4
-4
@@ -1,15 +1,15 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
fun useDeclaredVariables() {
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for ((a, b)<!SYNTAX!><!>) {
|
||||
for ((a, b)<!SYNTAX!><!>) {
|
||||
a
|
||||
b
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun checkersShouldRun() {
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for ((@A a, _)<!SYNTAX!><!>) {
|
||||
for ((@A a, _)<!SYNTAX!><!>) {
|
||||
|
||||
}<!>
|
||||
}
|
||||
}
|
||||
|
||||
annotation class A
|
||||
|
||||
+2
-2
@@ -11,6 +11,6 @@ fun test(nothing: Nothing?) {
|
||||
}
|
||||
|
||||
fun sum(a : IntArray) : Int {
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (n
|
||||
<!SYNTAX!>return<!><!SYNTAX!><!> "?"<!>
|
||||
for (n
|
||||
<!SYNTAX!>return<!><!SYNTAX!><!> "?"
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -1,8 +1,8 @@
|
||||
package b
|
||||
|
||||
fun foo() {
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (i in <!UNRESOLVED_REFERENCE!>collection<!>) {
|
||||
for (i in <!ITERATOR_MISSING, UNRESOLVED_REFERENCE!>collection<!>) {
|
||||
{
|
||||
break
|
||||
}
|
||||
}<!><!SYNTAX!><!>
|
||||
}<!SYNTAX!><!>
|
||||
|
||||
+2
-2
@@ -4,6 +4,6 @@ class X
|
||||
operator fun <T> X.iterator(): Iterable<T> = TODO()
|
||||
|
||||
fun test() {
|
||||
<!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (i in X()) {
|
||||
}<!>
|
||||
for (i in <!HAS_NEXT_MISSING!>X()<!>) {
|
||||
}
|
||||
}
|
||||
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
//KT-1821 Write test for ITERATOR_AMBIGUITY diagnostic
|
||||
|
||||
interface MyCollectionInterface {
|
||||
}
|
||||
|
||||
interface MyAnotherCollectionInterface {
|
||||
}
|
||||
|
||||
class MyCollection : MyCollectionInterface, MyAnotherCollectionInterface {
|
||||
}
|
||||
|
||||
fun MyCollectionInterface.iterator() = MyIterator()
|
||||
|
||||
fun MyAnotherCollectionInterface.iterator() = MyIterator()
|
||||
|
||||
class MyIterator {
|
||||
fun next() : MyElement = MyElement()
|
||||
fun hasNext() = true
|
||||
}
|
||||
|
||||
class MyElement
|
||||
|
||||
fun test1(collection: MyCollection) {
|
||||
collection.<!OVERLOAD_RESOLUTION_AMBIGUITY!>iterator<!>()
|
||||
<!OVERLOAD_RESOLUTION_AMBIGUITY, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (element in collection) {
|
||||
}<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
//KT-1821 Write test for ITERATOR_AMBIGUITY diagnostic
|
||||
|
||||
interface MyCollectionInterface {
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.*;
|
||||
import java.util.*;
|
||||
|
||||
public class J {
|
||||
@NotNull
|
||||
public static List<String> staticNN;
|
||||
@Nullable
|
||||
public static List<String> staticN;
|
||||
public static List<String> staticJ;
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
// @NotNull platform type
|
||||
val platformNN = J.staticNN
|
||||
// @Nullable platform type
|
||||
val platformN = J.staticN
|
||||
// platform type with no annotation
|
||||
val platformJ = J.staticJ
|
||||
|
||||
for (x in platformNN) {}
|
||||
<!UNSAFE_CALL!>for (x in platformN) {}<!>
|
||||
for (x in platformJ) {}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: J.java
|
||||
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
+2
-2
@@ -14,8 +14,8 @@ class MyClass {
|
||||
var res = 0
|
||||
m = create()
|
||||
// See KT-7428
|
||||
<!UNSAFE_CALL!>for ((k, v) in m)
|
||||
res += (k.length + v.length)<!>
|
||||
for ((k, v) in <!ITERATOR_ON_NULLABLE!>m<!>)
|
||||
res += (k.length + v.length)
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ fun whenInContract(x: Any?, boolean: Boolean) {
|
||||
|
||||
fun forInContract(x: Any?) {
|
||||
contract {
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION, UNRESOLVED_REFERENCE!>for (i in 0..1) {
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>for (i in 0..1) {
|
||||
returns() implies (x is String)
|
||||
}<!>
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -23,5 +23,5 @@ typealias C2<T> = JHost.Consumer2<T, T>
|
||||
val test1 = R { }
|
||||
val test2 = C<String> { s -> println(s.length) }
|
||||
val test3 = CStr { s -> <!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(s.<!UNRESOLVED_REFERENCE!>length<!>) }
|
||||
val test4 = CStrList { ss -> <!OVERLOAD_RESOLUTION_AMBIGUITY, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>for (s in ss) { <!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(s.<!UNRESOLVED_REFERENCE!>length<!>) }<!> }
|
||||
val test4 = CStrList { ss -> for (s in <!ITERATOR_AMBIGUITY!>ss<!>) { <!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(s.<!UNRESOLVED_REFERENCE!>length<!>) } }
|
||||
val test5 = <!INAPPLICABLE_CANDIDATE!>C2<!><Int> { a, b -> val x: Int = a <!OVERLOAD_RESOLUTION_AMBIGUITY!>+<!> b; println(x)}
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
* NOTE: right-hand side of an assignment must be expression
|
||||
*/
|
||||
fun case1() {
|
||||
val x = <!OVERLOAD_RESOLUTION_AMBIGUITY, UNRESOLVED_REFERENCE!>for (<!SYNTAX!><!>) { }<!>
|
||||
val x = for (<!SYNTAX!><!>) { }
|
||||
val y = for (x in 1..2) { }
|
||||
|
||||
val a = <!EXPRESSION_EXPECTED!>while (<!SYNTAX!><!>) { }<!>
|
||||
@@ -20,7 +20,7 @@ fun case1() {
|
||||
* NOTE: right-hand side of an assignment must be expression
|
||||
*/
|
||||
fun case2() {
|
||||
var x = <!OVERLOAD_RESOLUTION_AMBIGUITY, UNRESOLVED_REFERENCE!>for (<!SYNTAX!><!>) { }<!>
|
||||
var x = for (<!SYNTAX!><!>) { }
|
||||
var y = for (x in 1..2) { }
|
||||
|
||||
var a = <!EXPRESSION_EXPECTED!>while (<!SYNTAX!><!>) { }<!>
|
||||
@@ -40,7 +40,7 @@ fun case3() {
|
||||
var b :Any?
|
||||
var c :Any?
|
||||
|
||||
x = <!OVERLOAD_RESOLUTION_AMBIGUITY, UNRESOLVED_REFERENCE!>for (<!SYNTAX!><!>) { }<!>
|
||||
x = for (<!SYNTAX!><!>) { }
|
||||
y = for (x in 1..2) { }
|
||||
|
||||
a = <!EXPRESSION_EXPECTED!>while (<!SYNTAX!><!>) { }<!>
|
||||
|
||||
+69
@@ -823,6 +823,33 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.ITERATOR_AMBIGUITY) { firDiagnostic ->
|
||||
IteratorAmbiguityImpl(
|
||||
firDiagnostic.a.map { abstractFirBasedSymbol ->
|
||||
firSymbolBuilder.buildSymbol(abstractFirBasedSymbol.fir as FirDeclaration)
|
||||
},
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY) { firDiagnostic ->
|
||||
HasNextFunctionAmbiguityImpl(
|
||||
firDiagnostic.a.map { abstractFirBasedSymbol ->
|
||||
firSymbolBuilder.buildSymbol(abstractFirBasedSymbol.fir as FirDeclaration)
|
||||
},
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NEXT_AMBIGUITY) { firDiagnostic ->
|
||||
NextAmbiguityImpl(
|
||||
firDiagnostic.a.map { abstractFirBasedSymbol ->
|
||||
firSymbolBuilder.buildSymbol(abstractFirBasedSymbol.fir as FirDeclaration)
|
||||
},
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TYPE_MISMATCH) { firDiagnostic ->
|
||||
TypeMismatchImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
@@ -1704,6 +1731,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.ITERATOR_ON_NULLABLE) { firDiagnostic ->
|
||||
IteratorOnNullableImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.UNNECESSARY_SAFE_CALL) { firDiagnostic ->
|
||||
UnnecessarySafeCallImpl(
|
||||
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||
@@ -1784,6 +1817,42 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.ITERATOR_MISSING) { firDiagnostic ->
|
||||
IteratorMissingImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.HAS_NEXT_MISSING) { firDiagnostic ->
|
||||
HasNextMissingImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NEXT_MISSING) { firDiagnostic ->
|
||||
NextMissingImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.HAS_NEXT_FUNCTION_NONE_APPLICABLE) { firDiagnostic ->
|
||||
HasNextFunctionNoneApplicableImpl(
|
||||
firDiagnostic.a.map { abstractFirBasedSymbol ->
|
||||
firSymbolBuilder.buildSymbol(abstractFirBasedSymbol.fir as FirDeclaration)
|
||||
},
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NEXT_NONE_APPLICABLE) { firDiagnostic ->
|
||||
NextNoneApplicableImpl(
|
||||
firDiagnostic.a.map { abstractFirBasedSymbol ->
|
||||
firSymbolBuilder.buildSymbol(abstractFirBasedSymbol.fir as FirDeclaration)
|
||||
},
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TOPLEVEL_TYPEALIASES_ONLY) { firDiagnostic ->
|
||||
ToplevelTypealiasesOnlyImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
|
||||
+41
@@ -588,6 +588,21 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val candidates: List<KtSymbol>
|
||||
}
|
||||
|
||||
abstract class IteratorAmbiguity : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = IteratorAmbiguity::class
|
||||
abstract val candidates: List<KtSymbol>
|
||||
}
|
||||
|
||||
abstract class HasNextFunctionAmbiguity : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = HasNextFunctionAmbiguity::class
|
||||
abstract val candidates: List<KtSymbol>
|
||||
}
|
||||
|
||||
abstract class NextAmbiguity : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = NextAmbiguity::class
|
||||
abstract val candidates: List<KtSymbol>
|
||||
}
|
||||
|
||||
abstract class TypeMismatch : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = TypeMismatch::class
|
||||
abstract val expectedType: KtType
|
||||
@@ -1203,6 +1218,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val rhs: KtExpression
|
||||
}
|
||||
|
||||
abstract class IteratorOnNullable : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = IteratorOnNullable::class
|
||||
}
|
||||
|
||||
abstract class UnnecessarySafeCall : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = UnnecessarySafeCall::class
|
||||
abstract val receiverType: KtType
|
||||
@@ -1257,6 +1276,28 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = NoSetMethod::class
|
||||
}
|
||||
|
||||
abstract class IteratorMissing : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = IteratorMissing::class
|
||||
}
|
||||
|
||||
abstract class HasNextMissing : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = HasNextMissing::class
|
||||
}
|
||||
|
||||
abstract class NextMissing : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = NextMissing::class
|
||||
}
|
||||
|
||||
abstract class HasNextFunctionNoneApplicable : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = HasNextFunctionNoneApplicable::class
|
||||
abstract val candidates: List<KtSymbol>
|
||||
}
|
||||
|
||||
abstract class NextNoneApplicable : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = NextNoneApplicable::class
|
||||
abstract val candidates: List<KtSymbol>
|
||||
}
|
||||
|
||||
abstract class ToplevelTypealiasesOnly : KtFirDiagnostic<KtTypeAlias>() {
|
||||
override val diagnosticClass get() = ToplevelTypealiasesOnly::class
|
||||
}
|
||||
|
||||
+68
@@ -943,6 +943,30 @@ internal class AssignOperatorAmbiguityImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class IteratorAmbiguityImpl(
|
||||
override val candidates: List<KtSymbol>,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.IteratorAmbiguity(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class HasNextFunctionAmbiguityImpl(
|
||||
override val candidates: List<KtSymbol>,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.HasNextFunctionAmbiguity(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class NextAmbiguityImpl(
|
||||
override val candidates: List<KtSymbol>,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NextAmbiguity(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class TypeMismatchImpl(
|
||||
override val expectedType: KtType,
|
||||
override val actualType: KtType,
|
||||
@@ -1948,6 +1972,13 @@ internal class UnsafeOperatorCallImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class IteratorOnNullableImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.IteratorOnNullable(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class UnnecessarySafeCallImpl(
|
||||
override val receiverType: KtType,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
@@ -2038,6 +2069,43 @@ internal class NoSetMethodImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class IteratorMissingImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.IteratorMissing(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class HasNextMissingImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.HasNextMissing(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class NextMissingImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NextMissing(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class HasNextFunctionNoneApplicableImpl(
|
||||
override val candidates: List<KtSymbol>,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.HasNextFunctionNoneApplicable(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class NextNoneApplicableImpl(
|
||||
override val candidates: List<KtSymbol>,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NextNoneApplicable(), KtAbstractFirDiagnostic<KtExpression> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ToplevelTypealiasesOnlyImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
|
||||
Reference in New Issue
Block a user