[NI] Refactor compiler representation of integer literals types

Add `IntegerLiteralTypeConstructor` that holds types, that can take
  integer literal with given value. It has two supertypes
  (`Number` and `Comparable<IntegerLiteralType>`) and have
  special rules for subtyping, `intersect` and `commonSuperType`
  functions with primitive number:

Example (assuming that ILT holds Int type):
* ILT <: Int
* Int :> ILT
* ILT intersect Int = Int
* commonSuperType(ILT, Int) = Int

#KT-30293 Fixed
#KT-30446 Fixed
This commit is contained in:
Dmitriy Novozhilov
2019-03-18 18:03:23 +03:00
parent 9c3e452396
commit ca0e66bafc
30 changed files with 478 additions and 133 deletions
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionResultCallInfo
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils
@@ -510,8 +511,8 @@ class DelegatedPropertyResolver(
var delegateDataFlow = delegateTypeInfo.dataFlowInfo
val delegateTypeConstructor = delegateType.constructor
if (delegateTypeConstructor is IntegerValueTypeConstructor)
delegateType = TypeUtils.getDefaultPrimitiveNumberType(delegateTypeConstructor)
if (delegateTypeConstructor is IntegerLiteralTypeConstructor)
delegateType = delegateTypeConstructor.getApproximatedType()
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorProvideDelegate)) {
val contextForProvideDelegate = createContextForProvideDelegateMethod(
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
@@ -431,6 +432,12 @@ public class ArgumentTypeResolver {
constantExpressionEvaluator.updateNumberType(primitiveType, expression, statementFilter, trace);
return primitiveType;
}
if (typeConstructor instanceof IntegerLiteralTypeConstructor) {
IntegerLiteralTypeConstructor constructor = (IntegerLiteralTypeConstructor) typeConstructor;
KotlinType primitiveType = TypeUtils.getPrimitiveNumberType(constructor, expectedType);
constantExpressionEvaluator.updateNumberType(primitiveType, expression, statementFilter, trace);
return primitiveType;
}
}
return null;
}
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
@@ -634,10 +635,11 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
resultingDescriptor = run {
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
val containsIntegerLiteralTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it.constructor is IntegerLiteralTypeConstructor } ?: false
when {
candidateDescriptor is FunctionDescriptor ||
(candidateDescriptor is PropertyDescriptor && (candidateDescriptor.typeParameters.isNotEmpty() || containsCapturedTypes)) ->
(candidateDescriptor is PropertyDescriptor && (candidateDescriptor.typeParameters.isNotEmpty() || containsCapturedTypes || containsIntegerLiteralTypes)) ->
// this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types,
// but it seems like temporary solution.
candidateDescriptor.substitute(resolvedCallAtom.substitutor).substituteAndApproximateCapturedTypes(
@@ -650,7 +652,7 @@ class NewResolvedCallImpl<D : CallableDescriptor>(
typeArguments = resolvedCallAtom.substitutor.freshVariables.map {
val substituted = (substitutor ?: FreshVariableNewTypeSubstitutor.Empty).safeSubstitute(it.defaultType)
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedAndIntegerLiteralsTypesApproximation) ?: substituted
}
calculateExpedtedTypeForSamConvertedArgumentMap(substitutor)
@@ -971,7 +971,12 @@ private class ConstantExpressionEvaluatorVisitor(
}
if (TypeUtils.noExpectedType(expectedType) || expectedType.isError) {
return createIntegerValueTypeConstant(value, constantExpressionEvaluator.module, parameters)
return createIntegerValueTypeConstant(
value,
constantExpressionEvaluator.module,
parameters,
languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
)
}
val integerValue = ConstantValueFactory.createIntegerConstantValue(
value, expectedType, parameters.isUnsignedNumberLiteral