[NI] New inference -- initial commit.

This commit is contained in:
Stanislav Erokhin
2016-08-01 08:19:11 +03:00
parent 036090be91
commit b012681a53
64 changed files with 6089 additions and 63 deletions
@@ -230,14 +230,14 @@ public class ErrorUtils {
@Nullable
@Override
public ClassifierDescriptor getContributedClassifier(@NotNull Name name, @NotNull LookupLocation location) {
throw new IllegalStateException();
throw new IllegalStateException(debugMessage+", required name: " + name);
}
@NotNull
@Override
@SuppressWarnings({"unchecked"}) // KT-9898 Impossible implement kotlin interface from java
public Collection getContributedVariables(@NotNull Name name, @NotNull LookupLocation location) {
throw new IllegalStateException();
throw new IllegalStateException(debugMessage+", required name: " + name);
}
@NotNull
@@ -246,7 +246,7 @@ public class ErrorUtils {
// method is covariantly overridden in Kotlin, but collections in Java are invariant
@SuppressWarnings({"unchecked"})
public Collection getContributedFunctions(@NotNull Name name, @NotNull LookupLocation location) {
throw new IllegalStateException();
throw new IllegalStateException(debugMessage+", required name: " + name);
}
@NotNull
@@ -254,7 +254,7 @@ public class ErrorUtils {
public Collection<DeclarationDescriptor> getContributedDescriptors(
@NotNull DescriptorKindFilter kindFilter, @NotNull Function1<? super Name, Boolean> nameFilter
) {
throw new IllegalStateException();
throw new IllegalStateException(debugMessage);
}
@NotNull
@@ -18,6 +18,10 @@ package org.jetbrains.kotlin.types.checker
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.types.*
import java.util.*
import kotlin.collections.HashSet
fun intersectWrappedTypes(types: Collection<KotlinType>) = intersectTypes(types.map { it.unwrap() })
fun intersectTypes(types: List<UnwrappedType>): UnwrappedType {
when (types.size) {
@@ -58,7 +62,92 @@ fun intersectTypes(types: List<UnwrappedType>): UnwrappedType {
// types.size >= 2
// It is incorrect see to nullability here, because of KT-12684
private fun intersectTypes(types: List<SimpleType>): SimpleType {
val constructor = IntersectionTypeConstructor(types)
return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType())
return TypeIntersector.intersectTypes(types)
}
object TypeIntersector {
internal fun intersectTypes(types: List<SimpleType>): SimpleType {
assert(types.size > 1) {
"Size should be at least 2, but it is ${types.size}"
}
val inputTypes = ArrayList<SimpleType>()
for (type in types) {
if (type.constructor is IntersectionTypeConstructor) {
inputTypes.addAll(type.constructor.supertypes.map {
it.upperIfFlexible().let { if (type.isMarkedNullable) it.makeNullableAsSpecified(true) else it }
})
}
else {
inputTypes.add(type)
}
}
val resultNullability = inputTypes.fold(ResultNullability.START, ResultNullability::combine)
/**
* resultNullability. Value description:
* ACCEPT_NULL means that all types marked nullable
* NOT_NULL means that there is one type which is subtype of Any => all types can be marked not nullable
* UNKNOWN means, that we do not know, i.e. more precisely, all singleClassifier types marked nullable if any,
* and other types is captured types or type parameters without not-null upper bound. Example: `String? & T` such types we should leave as is.
*/
val correctNullability = inputTypes.mapTo(HashSet()) {
if (resultNullability == ResultNullability.NOT_NULL) it.makeNullableAsSpecified(false) else it
}
return intersectTypesWithoutIntersectionType(correctNullability)
}
// nullability here is correct
private fun intersectTypesWithoutIntersectionType(inputTypes: Set<SimpleType>): SimpleType {
// Any and Nothing should leave
// Note that duplicates should be dropped because we have Set here.
val filteredSupertypes = inputTypes.filterNot { upper ->
inputTypes.any { upper != it && NewKotlinTypeChecker.isSubtypeOf(it, upper) }
}
assert(filteredSupertypes.isNotEmpty()) {
"This collections cannot be empty! input types: ${inputTypes.joinToString()}"
}
if (filteredSupertypes.size < 2) return filteredSupertypes.single()
val constructor = IntersectionTypeConstructor(inputTypes)
return KotlinTypeFactory.simpleType(Annotations.EMPTY, constructor, listOf(), false, constructor.createScopeForKotlinType())
}
/**
* Let T is type parameter with upper bound Any?. resultNullability(String? & T) = UNKNOWN => String? & T
*/
private enum class ResultNullability {
START {
override fun combine(nextType: UnwrappedType) = nextType.resultNullability
},
ACCEPT_NULL {
override fun combine(nextType: UnwrappedType) = nextType.resultNullability
},
// example: type parameter without not-null supertype
UNKNOWN {
override fun combine(nextType: UnwrappedType) =
nextType.resultNullability.let {
if (it == ACCEPT_NULL) this else it
}
},
NOT_NULL {
override fun combine(nextType: UnwrappedType) = this
};
abstract fun combine(nextType: UnwrappedType): ResultNullability
protected val UnwrappedType.resultNullability: ResultNullability
get() {
if (isMarkedNullable) return ACCEPT_NULL
if (NullabilityChecker.isSubtypeOfAny(this)) {
return NOT_NULL
}
else {
return UNKNOWN
}
}
}
}
@@ -26,13 +26,52 @@ import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.utils.DO_NOTHING_2
// if input type is capturedType, then we approximate it to UpperBound
// null means that type should be leaved as is
fun prepareArgumentTypeRegardingCaptureTypes(argumentType: UnwrappedType): UnwrappedType? {
val simpleType = NewKotlinTypeChecker.transformToNewType(argumentType.lowerIfFlexible())
if (simpleType.constructor is IntersectionTypeConstructor){
var changed = false
val preparedSuperTypes = simpleType.constructor.supertypes.map {
prepareArgumentTypeRegardingCaptureTypes(it.unwrap())?.apply { changed = true } ?: it.unwrap()
}
if (!changed) return null
return intersectTypes(preparedSuperTypes).makeNullableAsSpecified(simpleType.isMarkedNullable)
}
if (simpleType is NewCapturedType) {
// todo may be we should respect flexible capture types also...
return simpleType.constructor.supertypes.takeIf { it.isNotEmpty() }?.let(::intersectTypes) ?: argumentType.builtIns.nullableAnyType
}
return captureFromExpression(simpleType)
}
fun captureFromExpression(type: UnwrappedType): UnwrappedType? = when (type) {
is SimpleType -> captureFromExpression(type)
// i.e. if there is nothing to capture -- no changes, if there is something -- use lowerBound as base type
is FlexibleType -> captureFromExpression(type.lowerBound)
}
fun captureFromExpression(type: SimpleType): UnwrappedType? {
val typeConstructor = type.constructor
if (typeConstructor is IntersectionTypeConstructor) {
var changed = false
val capturedSupertypes = typeConstructor.supertypes.map {
captureFromExpression(it.unwrap())?.apply { changed = true } ?: it.unwrap()
}
if (!changed) return null
return intersectTypes(capturedSupertypes).makeNullableAsSpecified(type.isMarkedNullable)
}
return captureFromArguments(type, CaptureStatus.FROM_EXPRESSION)
}
// this function suppose that input type is simple classifier type
fun captureFromArguments(
type: SimpleType,
status: CaptureStatus,
acceptNewCapturedType: ((argumentIndex: Int, NewCapturedType) -> Unit) = DO_NOTHING_2
): SimpleType {
): SimpleType? {
val arguments = type.arguments
if (arguments.all { it.projectionKind == Variance.INVARIANT }) return type
if (arguments.all { it.projectionKind == Variance.INVARIANT }) return null
val newArguments = arguments.map {
projection ->
@@ -68,6 +107,7 @@ fun captureFromArguments(
enum class CaptureStatus {
FOR_SUBTYPING,
FOR_INCORPORATION,
FROM_EXPRESSION
}
@@ -86,7 +126,7 @@ class NewCapturedType(
override val annotations: Annotations = Annotations.EMPTY,
override val isMarkedNullable: Boolean = false
): SimpleType() {
constructor(captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection) :
internal constructor(captureStatus: CaptureStatus, lowerType: UnwrappedType?, projection: TypeProjection) :
this(captureStatus, NewCapturedTypeConstructor(projection), lowerType)
override val arguments: List<TypeProjection> get() = listOf()
@@ -250,7 +250,7 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
var result: MutableList<SimpleType>? = null
anySupertype(baseType, { false }) {
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING)
val current = captureFromArguments(it, CaptureStatus.FOR_SUBTYPING) ?: it
when {
areEqualTypeConstructors(current.constructor, constructor) -> {
@@ -290,7 +290,7 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
return if (allPureSupertypes.isNotEmpty()) allPureSupertypes else supertypes
}
private fun effectiveVariance(declared: Variance, useSite: Variance): Variance? {
fun effectiveVariance(declared: Variance, useSite: Variance): Variance? {
if (declared == Variance.INVARIANT) return useSite
if (useSite == Variance.INVARIANT) return declared
@@ -341,12 +341,15 @@ object NullabilityChecker {
fun isPossibleSubtype(context: TypeCheckerContext, subType: SimpleType, superType: SimpleType): Boolean =
context.runIsPossibleSubtype(subType, superType)
fun isSubtypeOfAny(type: UnwrappedType): Boolean =
TypeCheckerContext(false).hasNotNullSupertype(type.lowerIfFlexible(), SupertypesPolicy.LowerIfFlexible)
private fun TypeCheckerContext.runIsPossibleSubtype(subType: SimpleType, superType: SimpleType): Boolean {
// it makes for case String? & Any <: String
assert(subType.isIntersectionType || subType.isSingleClassifierType || subType.isAllowedTypeVariable) {
"Not singleClassifierType superType: $superType"
}
assert(superType.isSingleClassifierType || subType.isAllowedTypeVariable) {
assert(superType.isSingleClassifierType || superType.isAllowedTypeVariable) {
"Not singleClassifierType superType: $superType"
}
@@ -391,7 +394,7 @@ object NullabilityChecker {
/**
* ClassType means that type constructor for this type is type for real class or interface
*/
private val SimpleType.isClassType: Boolean get() = constructor.declarationDescriptor is ClassDescriptor
val SimpleType.isClassType: Boolean get() = constructor.declarationDescriptor is ClassDescriptor
/**
* SingleClassifierType is one of the following types:
@@ -401,10 +404,10 @@ private val SimpleType.isClassType: Boolean get() = constructor.declarationDescr
*
* Such types can contains error types in our arguments, but type constructor isn't errorTypeConstructor
*/
private val SimpleType.isSingleClassifierType: Boolean
val SimpleType.isSingleClassifierType: Boolean
get() = !isError &&
constructor.declarationDescriptor !is TypeAliasDescriptor &&
(constructor.declarationDescriptor != null || this is CapturedType || this is NewCapturedType)
private val SimpleType.isIntersectionType: Boolean
val SimpleType.isIntersectionType: Boolean
get() = constructor is IntersectionTypeConstructor
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,7 +91,7 @@ public class DFS {
return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
}
private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
public static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
if (!visited.checkAndMarkVisited(current)) return;
if (!handler.beforeChildren(current)) return;