[NI] Add support ExpectedTypeFromCast to new inference. #KT-30405 Fixed

This commit is contained in:
Dmitriy Novozhilov
2019-03-14 14:14:28 +03:00
parent 9062811231
commit 1c92c22dee
12 changed files with 123 additions and 48 deletions
@@ -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
@@ -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
}