Minor: fix & reformat after rebase
This commit is contained in:
+2
-2
@@ -17,7 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
package org.jetbrains.kotlin.resolve.calls.checkers
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ enum class RttiOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class RttiExpressionInformation(
|
class RttiExpressionInformation(
|
||||||
val subject: KtExpression,
|
val subject: KtElement,
|
||||||
val sourceType: KotlinType?,
|
val sourceType: KotlinType?,
|
||||||
val targetType: KotlinType?,
|
val targetType: KotlinType?,
|
||||||
val operation: RttiOperation
|
val operation: RttiOperation
|
||||||
|
|||||||
+101
-85
@@ -85,11 +85,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
override fun visitWhenExpression(expression: KtWhenExpression, context: ExpressionTypingContext) =
|
override fun visitWhenExpression(expression: KtWhenExpression, context: ExpressionTypingContext) =
|
||||||
visitWhenExpression(expression, context, false)
|
visitWhenExpression(expression, context, false)
|
||||||
|
|
||||||
private sealed class Subject(
|
private abstract class Subject(
|
||||||
val element: KtElement?,
|
val element: KtElement?,
|
||||||
val typeInfo: KotlinTypeInfo?,
|
val typeInfo: KotlinTypeInfo?,
|
||||||
val scopeWithSubject: LexicalScope?,
|
val scopeWithSubject: LexicalScope?,
|
||||||
val type: KotlinType = typeInfo?.type ?: ErrorUtils.createErrorType("Unknown type")
|
val type: KotlinType = typeInfo?.type ?: ErrorUtils.createErrorType("Unknown type")
|
||||||
) {
|
) {
|
||||||
|
|
||||||
protected abstract fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns): DataFlowValue
|
protected abstract fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns): DataFlowValue
|
||||||
@@ -107,48 +107,47 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
|
|
||||||
val jumpOutPossible get() = typeInfo?.jumpOutPossible ?: false
|
val jumpOutPossible get() = typeInfo?.jumpOutPossible ?: false
|
||||||
|
|
||||||
|
|
||||||
class Expression(
|
class Expression(
|
||||||
val expression: KtExpression,
|
val expression: KtExpression,
|
||||||
typeInfo: KotlinTypeInfo
|
typeInfo: KotlinTypeInfo,
|
||||||
|
private val dataFlowValueFactory: DataFlowValueFactory
|
||||||
) : Subject(expression, typeInfo, null) {
|
) : Subject(expression, typeInfo, null) {
|
||||||
override fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns) =
|
override fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns) =
|
||||||
DataFlowValueFactory.createDataFlowValue(expression, type, contextAfterSubject)
|
dataFlowValueFactory.createDataFlowValue(expression, type, contextAfterSubject)
|
||||||
|
|
||||||
override fun makeValueArgument(): ValueArgument =
|
override fun makeValueArgument(): ValueArgument =
|
||||||
CallMaker.makeExternalValueArgument(expression)
|
CallMaker.makeExternalValueArgument(expression)
|
||||||
|
|
||||||
override val valueExpression: KtExpression
|
override val valueExpression: KtExpression
|
||||||
get() = expression
|
get() = expression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Variable(
|
class Variable(
|
||||||
val variable: KtProperty,
|
val variable: KtProperty,
|
||||||
val descriptor: VariableDescriptor,
|
val descriptor: VariableDescriptor,
|
||||||
typeInfo: KotlinTypeInfo,
|
typeInfo: KotlinTypeInfo,
|
||||||
scopeWithSubject: LexicalScope
|
scopeWithSubject: LexicalScope
|
||||||
) : Subject(variable, typeInfo, scopeWithSubject) {
|
) : Subject(variable, typeInfo, scopeWithSubject) {
|
||||||
override fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns) =
|
override fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns) =
|
||||||
DataFlowValue(
|
DataFlowValue(
|
||||||
IdentifierInfo.Variable(
|
IdentifierInfo.Variable(
|
||||||
descriptor,
|
descriptor,
|
||||||
DataFlowValue.Kind.STABLE_VALUE,
|
DataFlowValue.Kind.STABLE_VALUE,
|
||||||
contextAfterSubject.trace.bindingContext[BindingContext.BOUND_INITIALIZER_VALUE, descriptor]
|
contextAfterSubject.trace.bindingContext[BindingContext.BOUND_INITIALIZER_VALUE, descriptor]
|
||||||
),
|
),
|
||||||
descriptor.type
|
descriptor.type
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun makeValueArgument(): ValueArgument? =
|
override fun makeValueArgument(): ValueArgument? =
|
||||||
variable.initializer?.let {
|
variable.initializer?.let {
|
||||||
CallMaker.makeExternalValueArgument(
|
CallMaker.makeExternalValueArgument(
|
||||||
KtPsiFactory(variable.project, true).createExpression(variable.name!!),
|
KtPsiFactory(variable.project, true).createExpression(variable.name!!),
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeCalleeExpressionForSpecialCall(): KtExpression? =
|
override fun makeCalleeExpressionForSpecialCall(): KtExpression? =
|
||||||
KtPsiFactory(variable.project, true).createExpression(variable.name!!)
|
KtPsiFactory(variable.project, true).createExpression(variable.name!!)
|
||||||
|
|
||||||
override val valueExpression: KtExpression?
|
override val valueExpression: KtExpression?
|
||||||
get() = variable.initializer
|
get() = variable.initializer
|
||||||
@@ -157,7 +156,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
|
|
||||||
object None : Subject(null, null, null) {
|
object None : Subject(null, null, null) {
|
||||||
override fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns) =
|
override fun createDataFlowValue(contextAfterSubject: ExpressionTypingContext, builtIns: KotlinBuiltIns) =
|
||||||
DataFlowValue.nullValue(builtIns)
|
DataFlowValue.nullValue(builtIns)
|
||||||
|
|
||||||
override fun makeValueArgument(): ValueArgument? = null
|
override fun makeValueArgument(): ValueArgument? = null
|
||||||
|
|
||||||
@@ -185,9 +184,18 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
val subjectVariable = expression.subjectVariable
|
val subjectVariable = expression.subjectVariable
|
||||||
|
|
||||||
val subject = when {
|
val subject = when {
|
||||||
subjectVariable != null -> processVariableSubject(subjectVariable, contextBeforeSubject)
|
subjectVariable != null ->
|
||||||
subjectExpression != null -> Subject.Expression(subjectExpression, facade.getTypeInfo(subjectExpression, contextBeforeSubject))
|
processVariableSubject(subjectVariable, contextBeforeSubject)
|
||||||
else -> Subject.None
|
|
||||||
|
subjectExpression != null ->
|
||||||
|
Subject.Expression(
|
||||||
|
subjectExpression,
|
||||||
|
facade.getTypeInfo(subjectExpression, contextBeforeSubject),
|
||||||
|
components.dataFlowValueFactory
|
||||||
|
)
|
||||||
|
|
||||||
|
else ->
|
||||||
|
Subject.None
|
||||||
}
|
}
|
||||||
|
|
||||||
val contextAfterSubject = run {
|
val contextAfterSubject = run {
|
||||||
@@ -198,8 +206,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
}
|
}
|
||||||
|
|
||||||
val contextWithExpectedTypeAndSubjectVariable =
|
val contextWithExpectedTypeAndSubjectVariable =
|
||||||
subject.scopeWithSubject?.let { contextWithExpectedType.replaceScope(it) } ?:
|
subject.scopeWithSubject?.let { contextWithExpectedType.replaceScope(it) } ?: contextWithExpectedType
|
||||||
contextWithExpectedType
|
|
||||||
|
|
||||||
// val subjectType = subjectTypeInfo?.type ?: ErrorUtils.createErrorType("Unknown type")
|
// val subjectType = subjectTypeInfo?.type ?: ErrorUtils.createErrorType("Unknown type")
|
||||||
// val jumpOutPossibleInSubject: Boolean = subjectTypeInfo?.jumpOutPossible ?: false
|
// val jumpOutPossibleInSubject: Boolean = subjectTypeInfo?.jumpOutPossible ?: false
|
||||||
@@ -208,19 +215,24 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
// } ?: DataFlowValue.nullValue(components.builtIns)
|
// } ?: DataFlowValue.nullValue(components.builtIns)
|
||||||
subject.initDataFlowValue(contextAfterSubject, components.builtIns)
|
subject.initDataFlowValue(contextAfterSubject, components.builtIns)
|
||||||
|
|
||||||
val possibleTypesForSubject = subjectTypeInfo?.dataFlowInfo?.getStableTypes(
|
val possibleTypesForSubject =
|
||||||
subjectDataFlowValue, components.languageVersionSettings
|
subject.typeInfo?.dataFlowInfo?.getStableTypes(subject.dataFlowValue, components.languageVersionSettings)
|
||||||
) ?: emptySet()
|
?: emptySet()
|
||||||
checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subjectType, possibleTypesForSubject)
|
|
||||||
val possibleTypesForSubject = subject.typeInfo?.dataFlowInfo?.getStableTypes(subject.dataFlowValue) ?: emptySet()
|
|
||||||
checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subject.type, possibleTypesForSubject)
|
checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subject.type, possibleTypesForSubject)
|
||||||
|
|
||||||
val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subject)
|
val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subject)
|
||||||
val whenReturnType = inferTypeForWhenExpression(expression, subject, contextWithExpectedTypeAndSubjectVariable, contextAfterSubject, dataFlowInfoForEntries)
|
val whenReturnType = inferTypeForWhenExpression(
|
||||||
val whenResultValue = whenReturnType?.let { facade.components.dataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) }
|
expression,
|
||||||
|
subject,
|
||||||
|
contextWithExpectedTypeAndSubjectVariable,
|
||||||
|
contextAfterSubject,
|
||||||
|
dataFlowInfoForEntries
|
||||||
|
)
|
||||||
|
val whenResultValue =
|
||||||
|
whenReturnType?.let { facade.components.dataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) }
|
||||||
|
|
||||||
val branchesTypeInfo =
|
val branchesTypeInfo =
|
||||||
joinWhenExpressionBranches(expression, contextAfterSubject, whenReturnType, subject.jumpOutPossible, whenResultValue)
|
joinWhenExpressionBranches(expression, contextAfterSubject, whenReturnType, subject.jumpOutPossible, whenResultValue)
|
||||||
|
|
||||||
val isExhaustive = WhenChecker.isWhenExhaustive(expression, trace)
|
val isExhaustive = WhenChecker.isWhenExhaustive(expression, trace)
|
||||||
|
|
||||||
@@ -247,12 +259,13 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
val trace = contextBeforeSubject.trace
|
val trace = contextBeforeSubject.trace
|
||||||
|
|
||||||
if (!components.languageVersionSettings.supportsFeature(LanguageFeature.VariableDeclarationInWhenSubject)) {
|
if (!components.languageVersionSettings.supportsFeature(LanguageFeature.VariableDeclarationInWhenSubject)) {
|
||||||
trace.report(UNSUPPORTED_FEATURE.on(
|
trace.report(
|
||||||
|
UNSUPPORTED_FEATURE.on(
|
||||||
subjectVariable,
|
subjectVariable,
|
||||||
Pair(LanguageFeature.VariableDeclarationInWhenSubject, components.languageVersionSettings)
|
Pair(LanguageFeature.VariableDeclarationInWhenSubject, components.languageVersionSettings)
|
||||||
))
|
)
|
||||||
}
|
)
|
||||||
else {
|
} else {
|
||||||
val illegalDeclarationString = when {
|
val illegalDeclarationString = when {
|
||||||
subjectVariable is KtDestructuringDeclaration -> "destructuring declaration"
|
subjectVariable is KtDestructuringDeclaration -> "destructuring declaration"
|
||||||
subjectVariable.isVar -> "var"
|
subjectVariable.isVar -> "var"
|
||||||
@@ -267,10 +280,12 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val scopeWithSubjectVariable = ExpressionTypingUtils.newWritableScopeImpl(contextBeforeSubject, LexicalScopeKind.WHEN, components.overloadChecker)
|
val scopeWithSubjectVariable =
|
||||||
|
ExpressionTypingUtils.newWritableScopeImpl(contextBeforeSubject, LexicalScopeKind.WHEN, components.overloadChecker)
|
||||||
|
|
||||||
// Destructuring causes SOE in UAST :(
|
// Destructuring causes SOE in UAST :(
|
||||||
val resolveResult = components.localVariableResolver.process(subjectVariable, contextBeforeSubject, contextBeforeSubject.scope, facade)
|
val resolveResult =
|
||||||
|
components.localVariableResolver.process(subjectVariable, contextBeforeSubject, contextBeforeSubject.scope, facade)
|
||||||
val typeInfo = resolveResult.first
|
val typeInfo = resolveResult.first
|
||||||
val descriptor = resolveResult.second
|
val descriptor = resolveResult.second
|
||||||
|
|
||||||
@@ -285,11 +300,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun inferTypeForWhenExpression(
|
private fun inferTypeForWhenExpression(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
subject: Subject,
|
subject: Subject,
|
||||||
contextWithExpectedType: ExpressionTypingContext,
|
contextWithExpectedType: ExpressionTypingContext,
|
||||||
contextAfterSubject: ExpressionTypingContext,
|
contextAfterSubject: ExpressionTypingContext,
|
||||||
dataFlowInfoForEntries: List<DataFlowInfo>
|
dataFlowInfoForEntries: List<DataFlowInfo>
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
if (expression.entries.all { it.expression == null }) {
|
if (expression.entries.all { it.expression == null }) {
|
||||||
return components.builtIns.unitType
|
return components.builtIns.unitType
|
||||||
@@ -314,7 +329,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
},
|
},
|
||||||
Collections.nCopies(wrappedArgumentExpressions.size, false),
|
Collections.nCopies(wrappedArgumentExpressions.size, false),
|
||||||
contextWithExpectedType,
|
contextWithExpectedType,
|
||||||
dataFlowInfoForArguments)
|
dataFlowInfoForArguments
|
||||||
|
)
|
||||||
|
|
||||||
return resolvedCall.resultingDescriptor.returnType
|
return resolvedCall.resultingDescriptor.returnType
|
||||||
}
|
}
|
||||||
@@ -327,17 +343,17 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeConditionsInWhenEntries(
|
private fun analyzeConditionsInWhenEntries(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
contextAfterSubject: ExpressionTypingContext,
|
contextAfterSubject: ExpressionTypingContext,
|
||||||
subject: Subject
|
subject: Subject
|
||||||
): ArrayList<DataFlowInfo> {
|
): ArrayList<DataFlowInfo> {
|
||||||
val argumentDataFlowInfos = ArrayList<DataFlowInfo>()
|
val argumentDataFlowInfos = ArrayList<DataFlowInfo>()
|
||||||
var inputDataFlowInfo = contextAfterSubject.dataFlowInfo
|
var inputDataFlowInfo = contextAfterSubject.dataFlowInfo
|
||||||
for (whenEntry in expression.entries) {
|
for (whenEntry in expression.entries) {
|
||||||
val conditionsInfo = analyzeWhenEntryConditions(
|
val conditionsInfo = analyzeWhenEntryConditions(
|
||||||
whenEntry,
|
whenEntry,
|
||||||
contextAfterSubject.replaceDataFlowInfo(inputDataFlowInfo),
|
contextAfterSubject.replaceDataFlowInfo(inputDataFlowInfo),
|
||||||
subject
|
subject
|
||||||
)
|
)
|
||||||
inputDataFlowInfo = inputDataFlowInfo.and(conditionsInfo.elseInfo)
|
inputDataFlowInfo = inputDataFlowInfo.and(conditionsInfo.elseInfo)
|
||||||
|
|
||||||
@@ -371,7 +387,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
|
|
||||||
val entryDataFlowInfo =
|
val entryDataFlowInfo =
|
||||||
if (whenResultValue != null && entryType != null) {
|
if (whenResultValue != null && entryType != null) {
|
||||||
val entryValue = facade.components.dataFlowValueFactory.createDataFlowValue(entryExpression, entryType, contextAfterSubject)
|
val entryValue =
|
||||||
|
facade.components.dataFlowValueFactory.createDataFlowValue(entryExpression, entryType, contextAfterSubject)
|
||||||
entryTypeInfo.dataFlowInfo.assign(whenResultValue, entryValue, components.languageVersionSettings)
|
entryTypeInfo.dataFlowInfo.assign(whenResultValue, entryValue, components.languageVersionSettings)
|
||||||
} else {
|
} else {
|
||||||
entryTypeInfo.dataFlowInfo
|
entryTypeInfo.dataFlowInfo
|
||||||
@@ -446,9 +463,9 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeWhenEntryConditions(
|
private fun analyzeWhenEntryConditions(
|
||||||
whenEntry: KtWhenEntry,
|
whenEntry: KtWhenEntry,
|
||||||
context: ExpressionTypingContext,
|
context: ExpressionTypingContext,
|
||||||
subject: Subject
|
subject: Subject
|
||||||
): ConditionalDataFlowInfo {
|
): ConditionalDataFlowInfo {
|
||||||
if (whenEntry.isElse) {
|
if (whenEntry.isElse) {
|
||||||
return ConditionalDataFlowInfo(context.dataFlowInfo)
|
return ConditionalDataFlowInfo(context.dataFlowInfo)
|
||||||
@@ -469,9 +486,9 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkWhenCondition(
|
private fun checkWhenCondition(
|
||||||
subject: Subject,
|
subject: Subject,
|
||||||
condition: KtWhenCondition,
|
condition: KtWhenCondition,
|
||||||
context: ExpressionTypingContext
|
context: ExpressionTypingContext
|
||||||
): ConditionalDataFlowInfo {
|
): ConditionalDataFlowInfo {
|
||||||
var newDataFlowInfo = noChange(context)
|
var newDataFlowInfo = noChange(context)
|
||||||
|
|
||||||
@@ -512,10 +529,10 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
|
|
||||||
if (subject !is Subject.None) {
|
if (subject !is Subject.None) {
|
||||||
val rttiInformation = RttiExpressionInformation(
|
val rttiInformation = RttiExpressionInformation(
|
||||||
subject = subject.element!!,
|
subject = subject.element!!,
|
||||||
sourceType = subject.type,
|
sourceType = subject.type,
|
||||||
targetType = rhsType,
|
targetType = rhsType,
|
||||||
operation = if (condition.isNegated) RttiOperation.NOT_IS else RttiOperation.IS
|
operation = if (condition.isNegated) RttiOperation.NOT_IS else RttiOperation.IS
|
||||||
)
|
)
|
||||||
components.rttiExpressionCheckers.forEach {
|
components.rttiExpressionCheckers.forEach {
|
||||||
it.check(rttiInformation, condition, context.trace)
|
it.check(rttiInformation, condition, context.trace)
|
||||||
@@ -527,9 +544,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
override fun visitWhenConditionWithExpression(condition: KtWhenConditionWithExpression) {
|
override fun visitWhenConditionWithExpression(condition: KtWhenConditionWithExpression) {
|
||||||
val expression = condition.expression ?: return
|
val expression = condition.expression ?: return
|
||||||
|
|
||||||
val basicDataFlowInfo = checkTypeForExpressionCondition(context, expression, subject.type, subject is Subject.None, subject.dataFlowValue)
|
val basicDataFlowInfo =
|
||||||
|
checkTypeForExpressionCondition(context, expression, subject)
|
||||||
val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor)
|
val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor)
|
||||||
val dataFlowInfoFromES = components.effectSystem.getDataFlowInfoWhenEquals(subject.valueExpression, expression, context.trace, moduleDescriptor)
|
val dataFlowInfoFromES =
|
||||||
|
components.effectSystem.getDataFlowInfoWhenEquals(subject.valueExpression, expression, context.trace, moduleDescriptor)
|
||||||
newDataFlowInfo = basicDataFlowInfo.and(dataFlowInfoFromES)
|
newDataFlowInfo = basicDataFlowInfo.and(dataFlowInfoFromES)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,17 +562,14 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
private fun checkTypeForExpressionCondition(
|
private fun checkTypeForExpressionCondition(
|
||||||
context: ExpressionTypingContext,
|
context: ExpressionTypingContext,
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
subjectType: KotlinType,
|
subject: Subject
|
||||||
subjectExpression: KtExpression?,
|
|
||||||
subjectDataFlowValue: DataFlowValue
|
|
||||||
): ConditionalDataFlowInfo {
|
): ConditionalDataFlowInfo {
|
||||||
|
|
||||||
var newContext = context
|
var newContext = context
|
||||||
val typeInfo = facade.getTypeInfo(expression, newContext)
|
val typeInfo = facade.getTypeInfo(expression, newContext)
|
||||||
val type = typeInfo.type ?: return noChange(newContext)
|
val type = typeInfo.type ?: return noChange(newContext)
|
||||||
newContext = newContext.replaceDataFlowInfo(typeInfo.dataFlowInfo)
|
newContext = newContext.replaceDataFlowInfo(typeInfo.dataFlowInfo)
|
||||||
|
|
||||||
if (subjectExpression == null) { // condition expected
|
if (subject is Subject.None) { // condition expected
|
||||||
val booleanType = components.builtIns.booleanType
|
val booleanType = components.builtIns.booleanType
|
||||||
val checkedTypeInfo = components.dataFlowAnalyzer.checkType(typeInfo, expression, newContext.replaceExpectedType(booleanType))
|
val checkedTypeInfo = components.dataFlowAnalyzer.checkType(typeInfo, expression, newContext.replaceExpectedType(booleanType))
|
||||||
if (KotlinTypeChecker.DEFAULT.equalTypes(booleanType, checkedTypeInfo.type ?: type)) {
|
if (KotlinTypeChecker.DEFAULT.equalTypes(booleanType, checkedTypeInfo.type ?: type)) {
|
||||||
@@ -564,11 +580,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
return noChange(newContext)
|
return noChange(newContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkTypeCompatibility(newContext, type, subjectType, expression)
|
checkTypeCompatibility(newContext, type, subject.type, expression)
|
||||||
val expressionDataFlowValue = facade.components.dataFlowValueFactory.createDataFlowValue(expression, type, newContext)
|
val expressionDataFlowValue = facade.components.dataFlowValueFactory.createDataFlowValue(expression, type, newContext)
|
||||||
|
|
||||||
val subjectStableTypes =
|
val subjectStableTypes =
|
||||||
listOf(subjectType) + context.dataFlowInfo.getStableTypes(subjectDataFlowValue, components.languageVersionSettings)
|
listOf(subject.type) + context.dataFlowInfo.getStableTypes(subject.dataFlowValue, components.languageVersionSettings)
|
||||||
val expressionStableTypes =
|
val expressionStableTypes =
|
||||||
listOf(type) + newContext.dataFlowInfo.getStableTypes(expressionDataFlowValue, components.languageVersionSettings)
|
listOf(type) + newContext.dataFlowInfo.getStableTypes(expressionDataFlowValue, components.languageVersionSettings)
|
||||||
PrimitiveNumericComparisonCallChecker.inferPrimitiveNumericComparisonType(
|
PrimitiveNumericComparisonCallChecker.inferPrimitiveNumericComparisonType(
|
||||||
@@ -581,12 +597,12 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
val result = noChange(newContext)
|
val result = noChange(newContext)
|
||||||
return ConditionalDataFlowInfo(
|
return ConditionalDataFlowInfo(
|
||||||
result.thenInfo.equate(
|
result.thenInfo.equate(
|
||||||
subjectDataFlowValue, expressionDataFlowValue,
|
subject.dataFlowValue, expressionDataFlowValue,
|
||||||
identityEquals = facade.components.dataFlowAnalyzer.typeHasEqualsFromAny(subjectType, expression),
|
identityEquals = facade.components.dataFlowAnalyzer.typeHasEqualsFromAny(subject.type, expression),
|
||||||
languageVersionSettings = components.languageVersionSettings
|
languageVersionSettings = components.languageVersionSettings
|
||||||
),
|
),
|
||||||
result.elseInfo.disequate(
|
result.elseInfo.disequate(
|
||||||
subjectDataFlowValue,
|
subject.dataFlowValue,
|
||||||
expressionDataFlowValue,
|
expressionDataFlowValue,
|
||||||
components.languageVersionSettings
|
components.languageVersionSettings
|
||||||
)
|
)
|
||||||
|
|||||||
+13
-18
@@ -22462,62 +22462,57 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class WithSubjectVariable extends AbstractDiagnosticsTest {
|
public static class WithSubjectVariable extends AbstractDiagnosticsTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInWithSubjectVariable() throws Exception {
|
public void testAllFilesPresentInWithSubjectVariable() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/when/withSubjectVariable"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/when/withSubjectVariable"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("invisibleOutsideOfWhen.kt")
|
@TestMetadata("invisibleOutsideOfWhen.kt")
|
||||||
public void testInvisibleOutsideOfWhen() throws Exception {
|
public void testInvisibleOutsideOfWhen() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/invisibleOutsideOfWhen.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/invisibleOutsideOfWhen.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("reassignmentToWhenSubjectVariable.kt")
|
@TestMetadata("reassignmentToWhenSubjectVariable.kt")
|
||||||
public void testReassignmentToWhenSubjectVariable() throws Exception {
|
public void testReassignmentToWhenSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/reassignmentToWhenSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/reassignmentToWhenSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("shadowingOtherVariable.kt")
|
@TestMetadata("shadowingOtherVariable.kt")
|
||||||
public void testShadowingOtherVariable() throws Exception {
|
public void testShadowingOtherVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/shadowingOtherVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/shadowingOtherVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("smartCastOnValueBoundToSubjectVariable.kt")
|
@TestMetadata("smartCastOnValueBoundToSubjectVariable.kt")
|
||||||
public void testSmartCastOnValueBoundToSubjectVariable() throws Exception {
|
public void testSmartCastOnValueBoundToSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastOnValueBoundToSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastOnValueBoundToSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("smartCastsOnSubjectVariable.kt")
|
@TestMetadata("smartCastsOnSubjectVariable.kt")
|
||||||
public void testSmartCastsOnSubjectVariable() throws Exception {
|
public void testSmartCastsOnSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastsOnSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastsOnSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("subjectVariableInIsPattern.kt")
|
@TestMetadata("subjectVariableInIsPattern.kt")
|
||||||
public void testSubjectVariableInIsPattern() throws Exception {
|
public void testSubjectVariableInIsPattern() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/subjectVariableInIsPattern.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/subjectVariableInIsPattern.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("unsupportedFeature.kt")
|
@TestMetadata("unsupportedFeature.kt")
|
||||||
public void testUnsupportedFeature() throws Exception {
|
public void testUnsupportedFeature() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedFeature.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedFeature.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("unsupportedVariableDeclarationsInWhenSubject.kt")
|
@TestMetadata("unsupportedVariableDeclarationsInWhenSubject.kt")
|
||||||
public void testUnsupportedVariableDeclarationsInWhenSubject() throws Exception {
|
public void testUnsupportedVariableDeclarationsInWhenSubject() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("unusedWhenSubjectVariable.kt")
|
@TestMetadata("unusedWhenSubjectVariable.kt")
|
||||||
public void testUnusedWhenSubjectVariable() throws Exception {
|
public void testUnusedWhenSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/unusedWhenSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/unusedWhenSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+13
-18
@@ -22462,62 +22462,57 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class WithSubjectVariable extends AbstractDiagnosticsUsingJavacTest {
|
public static class WithSubjectVariable extends AbstractDiagnosticsUsingJavacTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInWithSubjectVariable() throws Exception {
|
public void testAllFilesPresentInWithSubjectVariable() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/when/withSubjectVariable"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/when/withSubjectVariable"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("invisibleOutsideOfWhen.kt")
|
@TestMetadata("invisibleOutsideOfWhen.kt")
|
||||||
public void testInvisibleOutsideOfWhen() throws Exception {
|
public void testInvisibleOutsideOfWhen() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/invisibleOutsideOfWhen.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/invisibleOutsideOfWhen.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("reassignmentToWhenSubjectVariable.kt")
|
@TestMetadata("reassignmentToWhenSubjectVariable.kt")
|
||||||
public void testReassignmentToWhenSubjectVariable() throws Exception {
|
public void testReassignmentToWhenSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/reassignmentToWhenSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/reassignmentToWhenSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("shadowingOtherVariable.kt")
|
@TestMetadata("shadowingOtherVariable.kt")
|
||||||
public void testShadowingOtherVariable() throws Exception {
|
public void testShadowingOtherVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/shadowingOtherVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/shadowingOtherVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("smartCastOnValueBoundToSubjectVariable.kt")
|
@TestMetadata("smartCastOnValueBoundToSubjectVariable.kt")
|
||||||
public void testSmartCastOnValueBoundToSubjectVariable() throws Exception {
|
public void testSmartCastOnValueBoundToSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastOnValueBoundToSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastOnValueBoundToSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("smartCastsOnSubjectVariable.kt")
|
@TestMetadata("smartCastsOnSubjectVariable.kt")
|
||||||
public void testSmartCastsOnSubjectVariable() throws Exception {
|
public void testSmartCastsOnSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastsOnSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/smartCastsOnSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("subjectVariableInIsPattern.kt")
|
@TestMetadata("subjectVariableInIsPattern.kt")
|
||||||
public void testSubjectVariableInIsPattern() throws Exception {
|
public void testSubjectVariableInIsPattern() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/subjectVariableInIsPattern.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/subjectVariableInIsPattern.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("unsupportedFeature.kt")
|
@TestMetadata("unsupportedFeature.kt")
|
||||||
public void testUnsupportedFeature() throws Exception {
|
public void testUnsupportedFeature() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedFeature.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedFeature.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("unsupportedVariableDeclarationsInWhenSubject.kt")
|
@TestMetadata("unsupportedVariableDeclarationsInWhenSubject.kt")
|
||||||
public void testUnsupportedVariableDeclarationsInWhenSubject() throws Exception {
|
public void testUnsupportedVariableDeclarationsInWhenSubject() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/unsupportedVariableDeclarationsInWhenSubject.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("unusedWhenSubjectVariable.kt")
|
@TestMetadata("unusedWhenSubjectVariable.kt")
|
||||||
public void testUnusedWhenSubjectVariable() throws Exception {
|
public void testUnusedWhenSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/withSubjectVariable/unusedWhenSubjectVariable.kt");
|
runTest("compiler/testData/diagnostics/tests/when/withSubjectVariable/unusedWhenSubjectVariable.kt");
|
||||||
doTest(fileName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -713,14 +713,12 @@ public class ParsingTestGenerated extends AbstractParsingTest {
|
|||||||
|
|
||||||
@TestMetadata("WhenWithSubjectVariable.kt")
|
@TestMetadata("WhenWithSubjectVariable.kt")
|
||||||
public void testWhenWithSubjectVariable() throws Exception {
|
public void testWhenWithSubjectVariable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/WhenWithSubjectVariable.kt");
|
runTest("compiler/testData/psi/WhenWithSubjectVariable.kt");
|
||||||
doParsingTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("WhenWithSubjectVariable_ERR.kt")
|
@TestMetadata("WhenWithSubjectVariable_ERR.kt")
|
||||||
public void testWhenWithSubjectVariable_ERR() throws Exception {
|
public void testWhenWithSubjectVariable_ERR() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/WhenWithSubjectVariable_ERR.kt");
|
runTest("compiler/testData/psi/WhenWithSubjectVariable_ERR.kt");
|
||||||
doParsingTest(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("When_ERR.kt")
|
@TestMetadata("When_ERR.kt")
|
||||||
|
|||||||
Reference in New Issue
Block a user