[NI] Add support ExpectedTypeFromCast to new inference. #KT-30405 Fixed
This commit is contained in:
+3
-39
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getBinaryWithTypeParent
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
@@ -40,12 +41,12 @@ import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.isFunctionForExpectTypeFromCastFeature
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -124,21 +125,6 @@ class GenericCandidateResolver(
|
||||
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.isFunctionForExpectTypeFromCastFeature(): Boolean {
|
||||
val typeParameter = typeParameters.singleOrNull() ?: return false
|
||||
|
||||
val returnType = returnType ?: return false
|
||||
if (returnType is DeferredType && returnType.isComputing) return false
|
||||
|
||||
if (returnType.constructor != typeParameter.typeConstructor) return false
|
||||
|
||||
fun KotlinType.isBadType() = contains { it.constructor == typeParameter.typeConstructor }
|
||||
|
||||
if (valueParameters.any { it.type.isBadType() } || extensionReceiverParameter?.type?.isBadType() == true) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun addExpectedTypeForExplicitCast(
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
builder: ConstraintSystem.Builder
|
||||
@@ -149,7 +135,7 @@ class GenericCandidateResolver(
|
||||
|
||||
val candidateDescriptor = context.candidateCall.candidateDescriptor.safeAs<FunctionDescriptor>() ?: return
|
||||
|
||||
val binaryParent = getBinaryWithTypeParent(context.call.calleeExpression) ?: return
|
||||
val binaryParent = context.call.calleeExpression?.getBinaryWithTypeParent() ?: return
|
||||
val operationType = binaryParent.operationReference.getReferencedNameElementType().takeIf {
|
||||
it == KtTokens.AS_KEYWORD || it == KtTokens.AS_SAFE
|
||||
} ?: return
|
||||
@@ -165,28 +151,6 @@ class GenericCandidateResolver(
|
||||
builder.addSubtypeConstraint(typeInSystem, expectedType, ConstraintPositionKind.SPECIAL.position())
|
||||
}
|
||||
|
||||
private fun getBinaryWithTypeParent(calleeExpression: KtExpression?): KtBinaryExpressionWithTypeRHS? {
|
||||
val callExpression = calleeExpression?.parent.safeAs<KtCallExpression>() ?: return null
|
||||
val possibleQualifiedExpression = callExpression.parent
|
||||
|
||||
val targetExpression = if (possibleQualifiedExpression is KtQualifiedExpression) {
|
||||
if (possibleQualifiedExpression.selectorExpression != callExpression) return null
|
||||
possibleQualifiedExpression
|
||||
} else {
|
||||
callExpression
|
||||
}
|
||||
|
||||
return targetExpression.topParenthesizedParentOrMe().parent.safeAs<KtBinaryExpressionWithTypeRHS>()
|
||||
}
|
||||
|
||||
private fun KtExpression.topParenthesizedParentOrMe(): KtExpression {
|
||||
var result: KtExpression = this
|
||||
while (KtPsiUtil.deparenthesizeOnce(result.parent.safeAs()) == result) {
|
||||
result = result.parent.safeAs() ?: break
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun addValidityConstraintsForConstituentTypes(builder: ConstraintSystem.Builder, type: KotlinType) {
|
||||
val typeConstructor = type.constructor
|
||||
if (typeConstructor.declarationDescriptor is TypeParameterDescriptor) return
|
||||
|
||||
+22
-4
@@ -11,16 +11,16 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isUnderKotlinPackage
|
||||
import org.jetbrains.kotlin.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtReturnExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getBinaryWithTypeParent
|
||||
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.TypeResolver
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
||||
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
|
||||
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -244,4 +245,21 @@ class KotlinResolutionCallbacksImpl(
|
||||
if (receiver == null) return callElement
|
||||
return PsiTreeUtil.findCommonParent(callElement, receiver.psiExpression)?.safeAs() ?: callElement
|
||||
}
|
||||
|
||||
override fun getExpectedTypeFromAsExpressionAndRecordItInTrace(resolvedAtom: ResolvedCallAtom): UnwrappedType? {
|
||||
val candidateDescriptor = resolvedAtom.candidateDescriptor as? FunctionDescriptor ?: return null
|
||||
val call = resolvedAtom.atom.safeAs<PSIKotlinCall>()?.psiCall ?: return null
|
||||
|
||||
if (call.typeArgumentList != null || !candidateDescriptor.isFunctionForExpectTypeFromCastFeature()) return null
|
||||
val binaryParent = call.calleeExpression?.getBinaryWithTypeParent() ?: return null
|
||||
val operationType = binaryParent.operationReference.getReferencedNameElementType().takeIf {
|
||||
it == KtTokens.AS_KEYWORD || it == KtTokens.AS_SAFE
|
||||
} ?: return null
|
||||
|
||||
val leftType = trace.get(BindingContext.TYPE, binaryParent.right ?: return null) ?: return null
|
||||
val expectedType = if (operationType == KtTokens.AS_SAFE) leftType.makeNullable() else leftType
|
||||
val resultType = expectedType.unwrap()
|
||||
trace.record(BindingContext.CAST_TYPE_USED_AS_EXPECTED_TYPE, binaryParent)
|
||||
return resultType
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.types.DeferredType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
|
||||
fun FunctionDescriptor.isFunctionForExpectTypeFromCastFeature(): Boolean {
|
||||
val typeParameter = typeParameters.singleOrNull() ?: return false
|
||||
|
||||
val returnType = returnType ?: return false
|
||||
if (returnType is DeferredType && returnType.isComputing) return false
|
||||
|
||||
if (returnType.constructor != typeParameter.typeConstructor) return false
|
||||
|
||||
fun KotlinType.isBadType() = contains { it.constructor == typeParameter.typeConstructor }
|
||||
|
||||
if (valueParameters.any { it.type.isBadType() } || extensionReceiverParameter?.type?.isBadType() == true) return false
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user