[NI] Approximate captured types when set them into variable.

Also do not store type with captured type inside possible types.
It is hack for now, but without it captured types can flow to
resolution and exception will be thrown.
This commit is contained in:
Stanislav Erokhin
2017-04-13 15:59:06 +03:00
parent 397103f9d0
commit 6aac67aa7e
4 changed files with 30 additions and 11 deletions
@@ -86,6 +86,7 @@ public class DescriptorResolver {
private final ModifiersChecker modifiersChecker; private final ModifiersChecker modifiersChecker;
private final WrappedTypeFactory wrappedTypeFactory; private final WrappedTypeFactory wrappedTypeFactory;
private final SyntheticResolveExtension syntheticResolveExtension; private final SyntheticResolveExtension syntheticResolveExtension;
private final TypeApproximator typeApproximator;
public DescriptorResolver( public DescriptorResolver(
@NotNull AnnotationResolver annotationResolver, @NotNull AnnotationResolver annotationResolver,
@@ -101,7 +102,8 @@ public class DescriptorResolver {
@NotNull DestructuringDeclarationResolver destructuringDeclarationResolver, @NotNull DestructuringDeclarationResolver destructuringDeclarationResolver,
@NotNull ModifiersChecker modifiersChecker, @NotNull ModifiersChecker modifiersChecker,
@NotNull WrappedTypeFactory wrappedTypeFactory, @NotNull WrappedTypeFactory wrappedTypeFactory,
@NotNull Project project @NotNull Project project,
TypeApproximator approximator
) { ) {
this.annotationResolver = annotationResolver; this.annotationResolver = annotationResolver;
this.builtIns = builtIns; this.builtIns = builtIns;
@@ -117,6 +119,7 @@ public class DescriptorResolver {
this.modifiersChecker = modifiersChecker; this.modifiersChecker = modifiersChecker;
this.wrappedTypeFactory = wrappedTypeFactory; this.wrappedTypeFactory = wrappedTypeFactory;
this.syntheticResolveExtension = SyntheticResolveExtension.Companion.getInstance(project); this.syntheticResolveExtension = SyntheticResolveExtension.Companion.getInstance(project);
typeApproximator = approximator;
} }
public List<KotlinType> resolveSupertypes( public List<KotlinType> resolveSupertypes(
@@ -666,11 +669,12 @@ public class DescriptorResolver {
BindingTrace trace, BindingTrace trace,
@NotNull LexicalScope scope @NotNull LexicalScope scope
) { ) {
UnwrappedType approximatedType = typeApproximator.approximateDeclarationType(type, true);
VariableDescriptor variableDescriptor = new LocalVariableDescriptor( VariableDescriptor variableDescriptor = new LocalVariableDescriptor(
scope.getOwnerDescriptor(), scope.getOwnerDescriptor(),
annotationResolver.resolveAnnotationsWithArguments(scope, parameter.getModifierList(), trace), annotationResolver.resolveAnnotationsWithArguments(scope, parameter.getModifierList(), trace),
KtPsiUtil.safeName(parameter.getName()), KtPsiUtil.safeName(parameter.getName()),
type, approximatedType,
false, false,
false, false,
KotlinSourceElementKt.toSourceElement(parameter) KotlinSourceElementKt.toSourceElement(parameter)
@@ -38,7 +38,8 @@ class VariableTypeAndInitializerResolver(
private val typeResolver: TypeResolver, private val typeResolver: TypeResolver,
private val constantExpressionEvaluator: ConstantExpressionEvaluator, private val constantExpressionEvaluator: ConstantExpressionEvaluator,
private val delegatedPropertyResolver: DelegatedPropertyResolver, private val delegatedPropertyResolver: DelegatedPropertyResolver,
private val wrappedTypeFactory: WrappedTypeFactory private val wrappedTypeFactory: WrappedTypeFactory,
private val typeApproximator: TypeApproximator
) { ) {
companion object { companion object {
@JvmField @JvmField
@@ -76,7 +77,7 @@ class VariableTypeAndInitializerResolver(
!variable.hasInitializer() && variable is KtProperty && variableDescriptor is VariableDescriptorWithAccessors && !variable.hasInitializer() && variable is KtProperty && variableDescriptor is VariableDescriptorWithAccessors &&
variable.hasDelegateExpression() -> variable.hasDelegateExpression() ->
resolveDelegatedPropertyType(variable, variableDescriptor, scopeForInitializer, dataFlowInfo, trace) resolveDelegatedPropertyType(variable, variableDescriptor, scopeForInitializer, dataFlowInfo, trace, local)
variable.hasInitializer() -> when { variable.hasInitializer() -> when {
!local -> !local ->
@@ -84,11 +85,11 @@ class VariableTypeAndInitializerResolver(
trace trace
) { ) {
PreliminaryDeclarationVisitor.createForDeclaration(variable, trace) PreliminaryDeclarationVisitor.createForDeclaration(variable, trace)
val initializerType = resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace) val initializerType = resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace) transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace)
} }
else -> resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace) else -> resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
} }
else -> null else -> null
} }
@@ -129,7 +130,8 @@ class VariableTypeAndInitializerResolver(
variableDescriptor: VariableDescriptorWithAccessors, variableDescriptor: VariableDescriptorWithAccessors,
scopeForInitializer: LexicalScope, scopeForInitializer: LexicalScope,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
trace: BindingTrace trace: BindingTrace,
local: Boolean
) = wrappedTypeFactory.createRecursionIntolerantDeferredType(trace) { ) = wrappedTypeFactory.createRecursionIntolerantDeferredType(trace) {
val delegateExpression = property.delegateExpression!! val delegateExpression = property.delegateExpression!!
val type = delegatedPropertyResolver.resolveDelegateExpression( val type = delegatedPropertyResolver.resolveDelegateExpression(
@@ -139,15 +141,18 @@ class VariableTypeAndInitializerResolver(
variableDescriptor, delegateExpression, type, trace, scopeForInitializer, dataFlowInfo variableDescriptor, delegateExpression, type, trace, scopeForInitializer, dataFlowInfo
) )
getterReturnType ?: ErrorUtils.createErrorType("Type from delegate") getterReturnType?.let { approximateType(it, local) } ?: ErrorUtils.createErrorType("Type from delegate")
} }
private fun resolveInitializerType( private fun resolveInitializerType(
scope: LexicalScope, scope: LexicalScope,
initializer: KtExpression, initializer: KtExpression,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
trace: BindingTrace trace: BindingTrace,
local: Boolean
): KotlinType { ): KotlinType {
return expressionTypingServices.safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo, trace) return approximateType(expressionTypingServices.safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo, trace), local)
} }
private fun approximateType(type: KotlinType, local: Boolean): UnwrappedType = typeApproximator.approximateDeclarationType(type, local)
} }
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.isFlexible import org.jetbrains.kotlin.types.isFlexible
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.typeUtil.contains
import java.util.* import java.util.*
internal class DelegatingDataFlowInfo private constructor( internal class DelegatingDataFlowInfo private constructor(
@@ -329,7 +331,7 @@ internal class DelegatingDataFlowInfo private constructor(
for (value in typeInfo.keys()) { for (value in typeInfo.keys()) {
for (type in typeInfo[value]) { for (type in typeInfo[value]) {
// Remove original type (see also KT-10666) // Remove original type (see also KT-10666)
if (value.type == type) { if (value.type == type || type.contains { it.constructor is NewCapturedTypeConstructor }) {
toDelete.put(value, type) toDelete.put(value, type)
} }
} }
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.types package org.jetbrains.kotlin.types
import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator import org.jetbrains.kotlin.resolve.calls.components.CommonSupertypeCalculator
import org.jetbrains.kotlin.resolve.calls.USE_NEW_INFERENCE
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.* import org.jetbrains.kotlin.types.TypeApproximatorConfiguration.IntersectionStrategy.*
import org.jetbrains.kotlin.types.checker.* import org.jetbrains.kotlin.types.checker.*
@@ -58,6 +59,7 @@ open class TypeApproximatorConfiguration {
object PublicDeclaration : AllFlexibleSameValue() { object PublicDeclaration : AllFlexibleSameValue() {
override val allFlexible get() = true override val allFlexible get() = true
override val errorType get() = true
} }
abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() { abstract class AbstractCapturedTypesApproximation(val approximatedCapturedStatus: CaptureStatus): TypeApproximatorConfiguration.AllFlexibleSameValue() {
@@ -78,6 +80,12 @@ class TypeApproximator(private val commonSupertypeCalculator: CommonSupertypeCal
private val referenceApproximateToSuperType = this::approximateToSuperType private val referenceApproximateToSuperType = this::approximateToSuperType
private val referenceApproximateToSubType = this::approximateToSubType private val referenceApproximateToSubType = this::approximateToSubType
fun approximateDeclarationType(baseType: KotlinType, local: Boolean): UnwrappedType {
if (!USE_NEW_INFERENCE) return baseType.unwrap()
val configuration = if (local) TypeApproximatorConfiguration.LocalDeclaration else TypeApproximatorConfiguration.PublicDeclaration
return approximateToSuperType(baseType.unwrap(), configuration) ?: baseType.unwrap()
}
// null means that this input type is the result, i.e. input type not contains not-allowed kind of types // null means that this input type is the result, i.e. input type not contains not-allowed kind of types
// type <: resultType // type <: resultType