[FIR] Implement ASSIGNMENT_TYPE_MISMATCH, RESULT_TYPE_MISMATCH diagnostics, fix tests

This commit is contained in:
Ivan Kochurkin
2021-04-19 12:12:49 +03:00
committed by TeamCityServer
parent aa70c952eb
commit e57108d4e8
40 changed files with 200 additions and 131 deletions
@@ -107,7 +107,7 @@ fun foo() {
if (bool) <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 4 else <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 42 if (bool) <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 4 else <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 42
val <!VARIABLE_NEVER_READ!>b<!>: String val <!VARIABLE_NEVER_READ!>b<!>: String
<!ASSIGNED_VALUE_IS_NEVER_READ!>b<!> = false <!ASSIGNED_VALUE_IS_NEVER_READ!>b<!> = <!ASSIGNMENT_TYPE_MISMATCH!>false<!>
} }
fun cycles() { fun cycles() {
@@ -5,5 +5,5 @@ fun foo() {
// now, Idea hightlights this code like error (cuz listVar // now, Idea hightlights this code like error (cuz listVar
// is mutable and listVar + 4 is immutable) and like warning // is mutable and listVar + 4 is immutable) and like warning
// (cuz can be replaced with +=) // (cuz can be replaced with +=)
<!ASSIGNED_VALUE_IS_NEVER_READ!>listVar<!> = listVar + 4 <!ASSIGNED_VALUE_IS_NEVER_READ!>listVar<!> = <!ASSIGNMENT_TYPE_MISMATCH!>listVar + 4<!>
} }
@@ -7,7 +7,7 @@ class B(p0: String) {
p3 = p1 p3 = p1
} }
init { init {
p1 = p0.length p1 = <!ASSIGNMENT_TYPE_MISMATCH!>p0.length<!>
p3 = "" p3 = ""
} }
} }
@@ -272,6 +272,16 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
parameter<String>("name") parameter<String>("name")
} }
val ASSIGNMENT_TYPE_MISMATCH by error<KtExpression> {
parameter<ConeKotlinType>("expected")
parameter<ConeKotlinType>("actual")
}
val RESULT_TYPE_MISMATCH by error<KtExpression> {
parameter<ConeKotlinType>("expected")
parameter<ConeKotlinType>("actual")
}
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>() val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
} }
@@ -226,6 +226,8 @@ object FirErrors {
val TOO_MANY_ARGUMENTS by error1<PsiElement, FirCallableDeclaration<*>>() val TOO_MANY_ARGUMENTS by error1<PsiElement, FirCallableDeclaration<*>>()
val NO_VALUE_FOR_PARAMETER by error1<KtElement, FirValueParameter>(SourceElementPositioningStrategies.VALUE_ARGUMENTS) val NO_VALUE_FOR_PARAMETER by error1<KtElement, FirValueParameter>(SourceElementPositioningStrategies.VALUE_ARGUMENTS)
val NAMED_PARAMETER_NOT_FOUND by error1<KtValueArgument, String>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT) val NAMED_PARAMETER_NOT_FOUND by error1<KtValueArgument, String>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
val ASSIGNMENT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
val RESULT_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>() val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
// Ambiguity // Ambiguity
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
@@ -33,8 +34,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtModifierList import org.jetbrains.kotlin.psi.KtModifierList
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
@@ -519,3 +519,45 @@ private val FirSimpleFunction.matchesHashCodeSignature: Boolean
private val FirSimpleFunction.matchesToStringSignature: Boolean private val FirSimpleFunction.matchesToStringSignature: Boolean
get() = valueParameters.isEmpty() get() = valueParameters.isEmpty()
fun checkTypeMismatch(
lValueType: ConeKotlinType,
rValue: FirExpression,
context: CheckerContext,
source: FirSourceElement,
reporter: DiagnosticReporter,
isInitializer: Boolean
) {
val rValueType = rValue.typeRef.coneType
val typeContext = context.session.typeContext
if (!isSubtypeForTypeMismatch(typeContext, subtype = rValueType, supertype = lValueType)) {
if (rValueType is ConeClassLikeType &&
rValueType.lookupTag.classId == StandardClassIds.Int &&
lValueType.fullyExpandedType(context.session).isIntegerTypeOrNullableIntegerTypeOfAnySize &&
rValueType.nullability == ConeNullability.NOT_NULL
) {
// val p: Byte = 42 or similar situation
// TODO: remove after fix of KT-46047
return
}
if (lValueType.isExtensionFunctionType || rValueType.isExtensionFunctionType) {
// TODO: remove after fix of KT-45989
return
}
if (rValue.isNullLiteral && lValueType.nullability == ConeNullability.NOT_NULL) {
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
} else {
val diagnosticFactory = when {
isInitializer ->
FirErrors.INITIALIZER_TYPE_MISMATCH
source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement ->
FirErrors.RESULT_TYPE_MISMATCH
else ->
FirErrors.ASSIGNMENT_TYPE_MISMATCH
}
reporter.report(diagnosticFactory.on(source, lValueType, rValueType), context)
}
}
}
@@ -7,18 +7,12 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirRealSourceElementKind import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.checkTypeMismatch
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeForTypeMismatch import org.jetbrains.kotlin.fir.analysis.checkers.isComponentCall
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_TYPE_MISMATCH
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.FirComponentCall import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.StandardClassIds
object FirInitializerTypeMismatchChecker : FirPropertyChecker() { object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -28,28 +22,7 @@ object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
if (initializer is FirComponentCall) return if (initializer is FirComponentCall) return
if (declaration.returnTypeRef.source?.kind != FirRealSourceElementKind) return if (declaration.returnTypeRef.source?.kind != FirRealSourceElementKind) return
val propertyType = declaration.returnTypeRef.coneType val propertyType = declaration.returnTypeRef.coneType
val expressionType = initializer.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
val typeContext = context.session.typeContext
if (!isSubtypeForTypeMismatch(typeContext, subtype = expressionType, supertype = propertyType)) { checkTypeMismatch(propertyType, initializer, context, source, reporter, true)
if (expressionType is ConeClassLikeType &&
expressionType.lookupTag.classId == StandardClassIds.Int &&
propertyType.fullyExpandedType(context.session).isIntegerTypeOrNullableIntegerTypeOfAnySize &&
expressionType.nullability == ConeNullability.NOT_NULL
) {
// val p: Byte = 42 or similar situation
// TODO: remove after fix of KT-46047
return
}
if (propertyType.isExtensionFunctionType || expressionType.isExtensionFunctionType) {
// TODO: remove after fix of KT-45989
return
}
if (initializer.isNullLiteral && propertyType.nullability == ConeNullability.NOT_NULL) {
reporter.reportOn(initializer.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
} else {
reporter.report(INITIALIZER_TYPE_MISMATCH.on(source, propertyType, expressionType), context)
}
}
} }
} }
@@ -5,25 +5,21 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.checkTypeMismatch
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.ConeNullability
import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isNullLiteral
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() { object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
val rValue = expression.rValue val source = expression.rValue.source ?: return
if (rValue.isNullLiteral) { val lValueType =
val leftType = ((expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirPropertySymbol)?.fir?.returnTypeRef ((expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirPropertySymbol)?.fir?.returnTypeRef?.coneType
if (leftType?.coneType?.nullability == ConeNullability.NOT_NULL) { ?: return
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
} checkTypeMismatch(lValueType, expression.rValue, context, source, reporter, false)
}
} }
} }
+12 -12
View File
@@ -22,10 +22,10 @@ class WrongIncDec() {
fun testWrongIncDec() { fun testWrongIncDec() {
var x = WrongIncDec() var x = WrongIncDec()
x++ <!RESULT_TYPE_MISMATCH!>x++<!>
++x <!RESULT_TYPE_MISMATCH!>++x<!>
x-- <!RESULT_TYPE_MISMATCH!>x--<!>
--x <!RESULT_TYPE_MISMATCH!>--x<!>
} }
class UnitIncDec() { class UnitIncDec() {
@@ -35,12 +35,12 @@ class UnitIncDec() {
fun testUnitIncDec() { fun testUnitIncDec() {
var x = UnitIncDec() var x = UnitIncDec()
x++ <!RESULT_TYPE_MISMATCH!>x++<!>
++x <!RESULT_TYPE_MISMATCH!>++x<!>
x-- <!RESULT_TYPE_MISMATCH!>x--<!>
--x <!RESULT_TYPE_MISMATCH!>--x<!>
x = x++ x = <!RESULT_TYPE_MISMATCH!>x++<!>
x = x-- x = <!RESULT_TYPE_MISMATCH!>x--<!>
x = ++x x = <!RESULT_TYPE_MISMATCH!>++x<!>
x = --x x = <!RESULT_TYPE_MISMATCH!>--x<!>
} }
@@ -13,7 +13,7 @@ class Q {
private var y = foo<String>() private var y = foo<String>()
fun bar() { fun bar() {
x = y x = <!ASSIGNMENT_TYPE_MISMATCH!>y<!>
x = foo<CharSequence>() x = foo<CharSequence>()
y = foo<String>() y = foo<String>()
@@ -29,7 +29,7 @@ fun <E> commonSupertype(x: E, y: E): E = x
fun foo() { fun foo() {
var myIt = A<String>().iterator() var myIt = A<String>().iterator()
myIt = A<Int>().iterator() myIt = <!ASSIGNMENT_TYPE_MISMATCH!>A<Int>().iterator()<!>
val csIt: Iterator<CharSequence> = A<String>().iterator() val csIt: Iterator<CharSequence> = A<String>().iterator()
@@ -11,7 +11,7 @@ class Outer<T> {
z.checkType { _<Inner>() } z.checkType { _<Inner>() }
z.checkType { _<Outer<T>.Inner>() } z.checkType { _<Outer<T>.Inner>() }
inner = x inner = <!ASSIGNMENT_TYPE_MISMATCH!>x<!>
} }
class Nested class Nested
@@ -12,7 +12,7 @@ fun <T : CharSequence?> foo(x: T) {
if (x != null) {} if (x != null) {}
y1 = x y1 = x
y2 = x y2 = <!ASSIGNMENT_TYPE_MISMATCH!>x<!>
bar1(x) bar1(x)
bar1<CharSequence>(x) bar1<CharSequence>(x)
@@ -31,7 +31,7 @@ fun <T : CharSequence?> foo(x: T) {
if (x is CharSequence) { if (x is CharSequence) {
y1 = x y1 = x
y2 = x y2 = <!ASSIGNMENT_TYPE_MISMATCH!>x<!>
bar1(x) bar1(x)
bar2(x) bar2(x)
@@ -24,10 +24,10 @@ class A<T : CharSequence?, E1 : T, E2: T?> {
} }
if (1 == 1) { if (1 == 1) {
t = tN t = <!ASSIGNMENT_TYPE_MISMATCH!>tN<!>
} }
t = y t = <!ASSIGNMENT_TYPE_MISMATCH!>y<!>
if (y != null) { if (y != null) {
t = y t = y
@@ -5,6 +5,6 @@ interface Tr<T> {
} }
fun test(t: Tr<*>) { fun test(t: Tr<*>) {
t.v = t t.v = <!ASSIGNMENT_TYPE_MISMATCH!>t<!>
t.v checkType { _<Tr<*>>() } t.v checkType { _<Tr<*>>() }
} }
@@ -8,7 +8,7 @@ interface Tr<T> {
fun test(t: Tr<*>) { fun test(t: Tr<*>) {
t.v = null!! t.v = null!!
t.v = "" t.v = <!ASSIGNMENT_TYPE_MISMATCH!>""<!>
t.v = <!NULL_FOR_NONNULL_TYPE!>null<!> t.v = <!NULL_FOR_NONNULL_TYPE!>null<!>
t.v checkType { _<Any?>() } t.v checkType { _<Any?>() }
} }
@@ -7,5 +7,5 @@ interface Tr<T> {
fun test(t: Tr<out String>) { fun test(t: Tr<out String>) {
// resolved as t.v = t.v + null!!, where type of right operand is String, // resolved as t.v = t.v + null!!, where type of right operand is String,
// so TYPE_MISMATCH: String is not <: of Captured(out String) // so TYPE_MISMATCH: String is not <: of Captured(out String)
t.v += null!! <!ASSIGNMENT_TYPE_MISMATCH!>t.v += null!!<!>
} }
@@ -3,15 +3,15 @@ fun intBinEq() {
x <!UNRESOLVED_REFERENCE!>+=<!> 'a' x <!UNRESOLVED_REFERENCE!>+=<!> 'a'
x += 1.toByte() x += 1.toByte()
x += 1.toShort() x += 1.toShort()
x += 1L <!ASSIGNMENT_TYPE_MISMATCH!>x += 1L<!>
x += 1f <!ASSIGNMENT_TYPE_MISMATCH!>x += 1f<!>
x += 1.0 <!ASSIGNMENT_TYPE_MISMATCH!>x += 1.0<!>
x <!UNRESOLVED_REFERENCE!>*=<!> 'a' x <!UNRESOLVED_REFERENCE!>*=<!> 'a'
x *= 1.toByte() <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1.toByte()<!>
x *= 1.toShort() <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1.toShort()<!>
x *= 1L <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1L<!>
x *= 1f <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1f<!>
x *= 1.0 <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1.0<!>
} }
fun shortBinEq() { fun shortBinEq() {
@@ -19,16 +19,16 @@ fun shortBinEq() {
x <!UNRESOLVED_REFERENCE!>+=<!> 'a' x <!UNRESOLVED_REFERENCE!>+=<!> 'a'
x += 1.toByte() x += 1.toByte()
x += 1.toShort() x += 1.toShort()
x += 1L <!ASSIGNMENT_TYPE_MISMATCH!>x += 1L<!>
x += 1f <!ASSIGNMENT_TYPE_MISMATCH!>x += 1f<!>
x += 1.0 <!ASSIGNMENT_TYPE_MISMATCH!>x += 1.0<!>
x <!UNRESOLVED_REFERENCE!>*=<!> 'a' x <!UNRESOLVED_REFERENCE!>*=<!> 'a'
x *= 1.toByte() <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1.toByte()<!>
x *= 1.toShort() <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1.toShort()<!>
x *= 1L <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1L<!>
x *= 1f <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1f<!>
x *= 1.0 <!ASSIGNMENT_TYPE_MISMATCH!>x *= 1.0<!>
} }
class A { class A {
@@ -44,5 +44,5 @@ fun overloading() {
var y = A() var y = A()
x += y x += y
var z = B() var z = B()
z += x <!ASSIGNMENT_TYPE_MISMATCH!>z += x<!>
} }
@@ -18,10 +18,10 @@ var n: J? = J()
fun test() { fun test() {
v = J.staticNN v = J.staticNN
v = J.staticN v = <!ASSIGNMENT_TYPE_MISMATCH!>J.staticN<!>
v = J.staticJ v = J.staticJ
n = J.staticNN n = J.staticNN
n = J.staticN n = J.staticN
n = J.staticJ n = J.staticJ
} }
@@ -34,8 +34,8 @@ fun foo(c: C) {
c.z checkType { _<String>() } c.z checkType { _<String>() }
c.y = "" c.y = ""
c.y = 1 c.y = <!ASSIGNMENT_TYPE_MISMATCH!>1<!>
c.z = "" c.z = ""
c.z = 1 c.z = <!ASSIGNMENT_TYPE_MISMATCH!>1<!>
} }
@@ -14,8 +14,8 @@ fun foo() {
noSetter checkType { _<Int>() } noSetter checkType { _<Int>() }
x = 1 x = 1
x = "" x = <!ASSIGNMENT_TYPE_MISMATCH!>""<!>
noSetter = 2 noSetter = 2
noSetter = "" noSetter = <!ASSIGNMENT_TYPE_MISMATCH!>""<!>
} }
@@ -15,7 +15,7 @@ fun a(c: Calendar) {
A().apply { A().apply {
c.apply { c.apply {
timeInMillis = 5 // synthesized variable for get|setTimeInMillis timeInMillis = 5 // synthesized variable for get|setTimeInMillis
timeInMillis = "" timeInMillis = <!ASSIGNMENT_TYPE_MISMATCH!>""<!>
} }
timeInMillis = "" timeInMillis = ""
} }
@@ -4,7 +4,7 @@ class IncDec {
fun foo(): IncDec { fun foo(): IncDec {
var x = IncDec() var x = IncDec()
x = x++ x = <!RESULT_TYPE_MISMATCH!>x++<!>
x++ <!RESULT_TYPE_MISMATCH!>x++<!>
return x return x
} }
@@ -1,5 +1,5 @@
// !DIAGNOSTICS: -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE // !DIAGNOSTICS: -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE
fun test() { fun test() {
var x = object {} var x = object {}
x = object {} x = <!ASSIGNMENT_TYPE_MISMATCH!>object<!> {}
} }
@@ -15,5 +15,5 @@ private fun foo() = run {
fun test() { fun test() {
var x = foo(1) var x = foo(1)
x = foo() x = <!ASSIGNMENT_TYPE_MISMATCH!>foo()<!>
} }
@@ -1,6 +1,6 @@
class Test { class Test {
private var x = object {}; private var x = object {};
init { init {
x = object {} x = <!ASSIGNMENT_TYPE_MISMATCH!>object<!> {}
} }
} }
@@ -19,5 +19,5 @@ private fun foo() = run {
fun test() { fun test() {
var x = foo(1) var x = foo(1)
x = foo() x = <!ASSIGNMENT_TYPE_MISMATCH!>foo()<!>
} }
@@ -19,5 +19,5 @@ private fun foo() = run {
fun test() { fun test() {
var x = foo(1) var x = foo(1)
x = foo() x = <!ASSIGNMENT_TYPE_MISMATCH!>foo()<!>
} }
@@ -1,5 +1,5 @@
private var x = object {} private var x = object {}
fun test() { fun test() {
x = object {} x = <!ASSIGNMENT_TYPE_MISMATCH!>object<!> {}
} }
@@ -29,7 +29,7 @@ fun foo(k: KotlinClass) {
useString(k.getSomething5()) useString(k.getSomething5())
useString(k.something5) useString(k.something5)
k.setSomething5(1) k.setSomething5(1)
k.something5 = 1 k.something5 = <!ASSIGNMENT_TYPE_MISMATCH!>1<!>
} }
fun useInt(i: Int) {} fun useInt(i: Int) {}
@@ -9,7 +9,7 @@ fun foo(k: KotlinClass) {
if (k.something == null) return if (k.something == null) return
k.setSomething(1) k.setSomething(1)
k.something = 1 k.something = <!ASSIGNMENT_TYPE_MISMATCH!>1<!>
} }
fun useString(i: String) {} fun useString(i: String) {}
@@ -4,7 +4,7 @@ fun foo(o: JavaClass2) {
useString(o.something) useString(o.something)
o.something = "" o.something = ""
o.setSomething(1) o.setSomething(1)
o.something = 1 // we generate extension property for JavaClass2 with more specific type o.something = <!ASSIGNMENT_TYPE_MISMATCH!>1<!> // we generate extension property for JavaClass2 with more specific type
o.something += "1" o.something += "1"
} }
@@ -19,4 +19,4 @@ public class JavaClass1 {
// FILE: JavaClass2.java // FILE: JavaClass2.java
public class JavaClass2 extends JavaClass1 { public class JavaClass2 extends JavaClass1 {
public String getSomething() { return ""; } public String getSomething() { return ""; }
} }
@@ -1,6 +1,6 @@
class My { class My {
var x: String = "" var x: String = ""
set(vararg value) { set(vararg value) {
x = value x = <!ASSIGNMENT_TYPE_MISMATCH!>value<!>
} }
} }
@@ -6,7 +6,7 @@
fun case1() { fun case1() {
var a = Case1() var a = Case1()
val res: Any? = ++a val res: Any? = <!RESULT_TYPE_MISMATCH!>++a<!>
} }
@@ -23,7 +23,7 @@ class B() {}
fun case2() { fun case2() {
var a = Case2() var a = Case2()
val res: Any? = ++a val res: Any? = <!RESULT_TYPE_MISMATCH!>++a<!>
} }
class Case2() : C() { class Case2() : C() {
@@ -6,7 +6,7 @@
fun case1() { fun case1() {
var a = Case1() var a = Case1()
val res: Any? = --a val res: Any? = <!RESULT_TYPE_MISMATCH!>--a<!>
} }
@@ -23,7 +23,7 @@ class B() {}
fun case2() { fun case2() {
var a = Case2() var a = Case2()
val res: Any? = --a val res: Any? = <!RESULT_TYPE_MISMATCH!>--a<!>
} }
class Case2() : C() { class Case2() : C() {
@@ -53,7 +53,7 @@ fun case_9() {
// TESTCASE NUMBER: 10 // TESTCASE NUMBER: 10
fun case_10(x: Int?) { fun case_10(x: Int?) {
var y = 10 var y = 10
y = x y = <!ASSIGNMENT_TYPE_MISMATCH!>x<!>
} }
// TESTCASE NUMBER: 11 // TESTCASE NUMBER: 11
@@ -914,6 +914,22 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.ASSIGNMENT_TYPE_MISMATCH) { firDiagnostic ->
AssignmentTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.RESULT_TYPE_MISMATCH) { firDiagnostic ->
ResultTypeMismatchImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY) { firDiagnostic -> add(FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY) { firDiagnostic ->
OverloadResolutionAmbiguityImpl( OverloadResolutionAmbiguityImpl(
firDiagnostic.a.map { abstractFirBasedSymbol -> firDiagnostic.a.map { abstractFirBasedSymbol ->
@@ -649,6 +649,18 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val name: String abstract val name: String
} }
abstract class AssignmentTypeMismatch : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = AssignmentTypeMismatch::class
abstract val expected: KtType
abstract val actual: KtType
}
abstract class ResultTypeMismatch : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = ResultTypeMismatch::class
abstract val expected: KtType
abstract val actual: KtType
}
abstract class ManyLambdaExpressionArguments : KtFirDiagnostic<KtValueArgument>() { abstract class ManyLambdaExpressionArguments : KtFirDiagnostic<KtValueArgument>() {
override val diagnosticClass get() = ManyLambdaExpressionArguments::class override val diagnosticClass get() = ManyLambdaExpressionArguments::class
} }
@@ -1046,6 +1046,24 @@ internal class NamedParameterNotFoundImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
} }
internal class AssignmentTypeMismatchImpl(
override val expected: KtType,
override val actual: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.AssignmentTypeMismatch(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ResultTypeMismatchImpl(
override val expected: KtType,
override val actual: KtType,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.ResultTypeMismatch(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ManyLambdaExpressionArgumentsImpl( internal class ManyLambdaExpressionArgumentsImpl(
firDiagnostic: FirPsiDiagnostic<*>, firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken, override val token: ValidityToken,
+12 -12
View File
@@ -22,10 +22,10 @@ class WrongIncDec() {
fun testWrongIncDec() { fun testWrongIncDec() {
var x = WrongIncDec() var x = WrongIncDec()
x++ <error descr="[RESULT_TYPE_MISMATCH] WrongIncDec, kotlin/Int">x++</error>
++x <error descr="[RESULT_TYPE_MISMATCH] WrongIncDec, kotlin/Int">++x</error>
x-- <error descr="[RESULT_TYPE_MISMATCH] WrongIncDec, kotlin/Int">x--</error>
--x <error descr="[RESULT_TYPE_MISMATCH] WrongIncDec, kotlin/Int">--x</error>
} }
class UnitIncDec() { class UnitIncDec() {
@@ -35,12 +35,12 @@ class UnitIncDec() {
fun testUnitIncDec() { fun testUnitIncDec() {
var x = UnitIncDec() var x = UnitIncDec()
x++ <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">x++</error>
++x <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">++x</error>
x-- <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">x--</error>
--x <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">--x</error>
x = x++ x = <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">x++</error>
x = x-- x = <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">x--</error>
x = ++x x = <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">++x</error>
x = --x x = <error descr="[RESULT_TYPE_MISMATCH] UnitIncDec, kotlin/Unit">--x</error>
} }