NI: Improve postponed arguments analysis

Introduce seven stages:
1) Analyze postponed arguments with fixed parameter types
2) Collect parameter types from constraints and lambda parameters' declaration
3) Fix not postponed variables for parameter types of all postponed arguments
4) Create atoms with revised expected types if needed
5) Analyze the first ready postponed argument and rerun stages if it has been analyzed
6) Force fixation remaining type variables: fix if possible or report not enough information
7) Force analysis remaining not analyzed postponed arguments and rerun stages if there are

^KT-37952 Fixed
^KT-32156 Fixed
^KT-37249 Fixed
^KT-37341 Fixed
This commit is contained in:
Victor Petukhov
2020-03-28 20:40:29 +03:00
parent 50151e0e01
commit 260683c20e
70 changed files with 2619 additions and 352 deletions
@@ -442,6 +442,11 @@ public abstract class KotlinBuiltIns {
return "Function" + parameterCount;
}
@NotNull
private static FqNameUnsafe getKFunctionFqName(int parameterCount) {
return FqNames.reflect(FunctionClassDescriptor.Kind.KFunction.getClassNamePrefix() + parameterCount);
}
@NotNull
public static ClassId getFunctionClassId(int parameterCount) {
return new ClassId(BUILT_INS_PACKAGE_FQ_NAME, Name.identifier(getFunctionName(parameterCount)));
@@ -467,6 +472,17 @@ public abstract class KotlinBuiltIns {
return getBuiltInClassByFqName(COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(Name.identifier(getSuspendFunctionName(parameterCount))));
}
@NotNull
public ClassDescriptor getKFunction(int parameterCount) {
return getBuiltInClassByFqName(getKFunctionFqName(parameterCount).toSafe());
}
@NotNull
public ClassDescriptor getKSuspendFunction(int parameterCount) {
Name name = Name.identifier(FunctionClassDescriptor.Kind.KSuspendFunction.getClassNamePrefix() + parameterCount);
return getBuiltInClassByFqName(COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(name));
}
@NotNull
public ClassDescriptor getThrowable() {
return getBuiltInClassByName("Throwable");
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
import org.jetbrains.kotlin.types.typeUtil.supertypes
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
@@ -67,6 +69,9 @@ val KotlinType.isKSuspendFunctionType: Boolean
val KotlinType.isFunctionOrSuspendFunctionType: Boolean
get() = isFunctionType || isSuspendFunctionType
val KotlinType.isFunctionOrKFunctionTypeWithAnySuspendability: Boolean
get() = isFunctionType || isSuspendFunctionType || isKFunctionType || isKSuspendFunctionType
val KotlinType.isBuiltinFunctionalType: Boolean
get() = constructor.declarationDescriptor?.isBuiltinFunctionalClassDescriptor == true
@@ -154,6 +159,16 @@ fun KotlinType.getValueParameterTypesFromCallableReflectionType(isCallableTypeWi
return arguments.subList(first, last)
}
fun KotlinType.extractFunctionalTypeFromSupertypes(): KotlinType {
assert(isBuiltinFunctionalTypeOrSubtype) { "Not a function type or subtype: $this" }
return if (isBuiltinFunctionalType) this else supertypes().first { it.isBuiltinFunctionalType }
}
fun KotlinType.getPureArgumentsForFunctionalTypeOrSubtype(): List<KotlinType> {
assert(isBuiltinFunctionalTypeOrSubtype) { "Not a function type or subtype: $this" }
return extractFunctionalTypeFromSupertypes().arguments.dropLast(1).map { it.type }
}
fun KotlinType.extractParameterNameFromFunctionTypeArgument(): Name? {
val annotation = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.parameterName) ?: return null
val name = (annotation.allValueArguments.values.singleOrNull() as? StringValue)
@@ -197,29 +212,38 @@ fun getFunctionTypeArgumentProjections(
@JvmOverloads
fun createFunctionType(
builtIns: KotlinBuiltIns,
annotations: Annotations,
receiverType: KotlinType?,
parameterTypes: List<KotlinType>,
parameterNames: List<Name>?,
returnType: KotlinType,
suspendFunction: Boolean = false
builtIns: KotlinBuiltIns,
annotations: Annotations,
receiverType: KotlinType?,
parameterTypes: List<KotlinType>,
parameterNames: List<Name>?,
returnType: KotlinType,
suspendFunction: Boolean = false
): SimpleType {
val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, parameterNames, returnType, builtIns)
val size = parameterTypes.size
val parameterCount = if (receiverType == null) size else size + 1
val classDescriptor = if (suspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount)
val parameterCount = if (receiverType == null) parameterTypes.size else parameterTypes.size + 1
val classDescriptor = getFunctionDescriptor(builtIns, parameterCount, suspendFunction)
// TODO: preserve laziness of given annotations
val typeAnnotations =
if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) {
annotations
}
else {
Annotations.create(
annotations + BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.extensionFunctionType, emptyMap())
)
}
val typeAnnotations = if (receiverType != null) annotations.withExtensionFunctionAnnotation(builtIns) else annotations
return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments)
}
fun Annotations.hasExtensionFunctionAnnotation() = hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType)
fun Annotations.withoutExtensionFunctionAnnotation() =
FilteredAnnotations(this, true) { it != KotlinBuiltIns.FQ_NAMES.extensionFunctionType }
fun Annotations.withExtensionFunctionAnnotation(builtIns: KotlinBuiltIns) =
if (hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType)) {
this
} else {
Annotations.create(this + BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.extensionFunctionType, emptyMap()))
}
fun getFunctionDescriptor(builtIns: KotlinBuiltIns, parameterCount: Int, isSuspendFunction: Boolean) =
if (isSuspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount)
fun getKFunctionDescriptor(builtIns: KotlinBuiltIns, parameterCount: Int, isSuspendFunction: Boolean) =
if (isSuspendFunction) builtIns.getKSuspendFunction(parameterCount) else builtIns.getKFunction(parameterCount)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -318,6 +319,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return KotlinBuiltIns.isUnit(this)
}
override fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean {
require(this is UnwrappedType, this::errorMessage)
return isBuiltinFunctionalTypeOrSubtype
}
override fun createFlexibleType(lowerBound: SimpleTypeMarker, upperBound: SimpleTypeMarker): KotlinTypeMarker {
require(lowerBound is SimpleType, this::errorMessage)
require(upperBound is SimpleType, this::errorMessage)
@@ -132,6 +132,8 @@ interface TypeSystemInferenceExtensionContext : TypeSystemContext, TypeSystemBui
fun KotlinTypeMarker.isUnit(): Boolean
fun KotlinTypeMarker.isBuiltinFunctionalTypeOrSubtype(): Boolean
fun KotlinTypeMarker.withNullability(nullable: Boolean): KotlinTypeMarker