Get rid of passing typeChecker from the call hierarchy

This commit is contained in:
Mikhail Zarechenskiy
2017-09-01 14:15:30 +03:00
parent e7449a3584
commit 0dc29d6d7e
11 changed files with 27 additions and 33 deletions
@@ -51,7 +51,6 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.ResolveConstruct
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
@@ -255,7 +254,7 @@ class GenericCandidateResolver(
val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue) val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue)
if (possibleTypes.isEmpty()) return type if (possibleTypes.isEmpty()) return type
return TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, possibleTypes + type) return TypeIntersector.intersectTypes(possibleTypes + type)
} }
fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(context: CallCandidateResolutionContext<D>) { fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(context: CallCandidateResolutionContext<D>) {
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -124,7 +124,7 @@ class TypeBoundsImpl(override val typeVariable: TypeVariable) : TypeBounds {
val upperBounds = filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND, values) val upperBounds = filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND, values)
if (upperBounds.isNotEmpty()) { if (upperBounds.isNotEmpty()) {
val intersectionOfUpperBounds = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, upperBounds) val intersectionOfUpperBounds = TypeIntersector.intersectTypes(upperBounds)
if (intersectionOfUpperBounds != null && tryPossibleAnswer(bounds, intersectionOfUpperBounds)) { if (intersectionOfUpperBounds != null && tryPossibleAnswer(bounds, intersectionOfUpperBounds)) {
return setOf(intersectionOfUpperBounds) return setOf(intersectionOfUpperBounds)
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,9 +21,9 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE import org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE
import org.jetbrains.kotlin.psi.Call import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.* import org.jetbrains.kotlin.resolve.BindingContext.IMPLICIT_RECEIVER_SMARTCAST
import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeIntersector import org.jetbrains.kotlin.types.TypeIntersector
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import java.util.* import java.util.*
class SmartCastManager { class SmartCastManager {
@@ -100,7 +99,7 @@ class SmartCastManager {
.distinct() .distinct()
if (subTypes.isEmpty()) return null if (subTypes.isEmpty()) return null
val intersection = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, subTypes) val intersection = TypeIntersector.intersectTypes(subTypes)
if (intersection == null || !intersection.constructor.isDenotable) { if (intersection == null || !intersection.constructor.isDenotable) {
return receiverParameterType return receiverParameterType
} }
@@ -203,28 +203,26 @@ object CastDiagnosticsUtil {
expression: KtBinaryExpressionWithTypeRHS, expression: KtBinaryExpressionWithTypeRHS,
context: ExpressionTypingContext, context: ExpressionTypingContext,
targetType: KotlinType, targetType: KotlinType,
actualType: KotlinType, actualType: KotlinType
typeChecker: KotlinTypeChecker
): Boolean { ): Boolean {
// Here: x as? Type <=> x as Type? // Here: x as? Type <=> x as Type?
val refinedTargetType = if (KtPsiUtil.isSafeCast(expression)) TypeUtils.makeNullable(targetType) else targetType val refinedTargetType = if (KtPsiUtil.isSafeCast(expression)) TypeUtils.makeNullable(targetType) else targetType
val possibleTypes = DataFlowAnalyzer.getAllPossibleTypes(expression.left, actualType, context) val possibleTypes = DataFlowAnalyzer.getAllPossibleTypes(expression.left, actualType, context)
return isRefinementUseless(possibleTypes, refinedTargetType, typeChecker, shouldCheckForExactType(expression, context.expectedType)) return isRefinementUseless(possibleTypes, refinedTargetType, shouldCheckForExactType(expression, context.expectedType))
} }
// It is a warning "useless cast" for `as` and a warning "redundant is" for `is` // It is a warning "useless cast" for `as` and a warning "redundant is" for `is`
fun isRefinementUseless( fun isRefinementUseless(
possibleTypes: Collection<KotlinType>, possibleTypes: Collection<KotlinType>,
targetType: KotlinType, targetType: KotlinType,
typeChecker: KotlinTypeChecker,
shouldCheckForExactType: Boolean shouldCheckForExactType: Boolean
): Boolean { ): Boolean {
val intersectedType = TypeIntersector.intersectTypes(typeChecker, possibleTypes.map { it.upperIfFlexible() }) ?: return false val intersectedType = TypeIntersector.intersectTypes(possibleTypes.map { it.upperIfFlexible() }) ?: return false
return if (shouldCheckForExactType) return if (shouldCheckForExactType)
isExactTypeCast(intersectedType, targetType) isExactTypeCast(intersectedType, targetType)
else else
isUpcast(intersectedType, targetType, typeChecker) isUpcast(intersectedType, targetType)
} }
private fun shouldCheckForExactType(expression: KtBinaryExpressionWithTypeRHS, expectedType: KotlinType): Boolean { private fun shouldCheckForExactType(expression: KtBinaryExpressionWithTypeRHS, expectedType: KotlinType): Boolean {
@@ -241,8 +239,8 @@ object CastDiagnosticsUtil {
return candidateType == targetType && candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType return candidateType == targetType && candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
} }
private fun isUpcast(candidateType: KotlinType, targetType: KotlinType, typeChecker: KotlinTypeChecker): Boolean { private fun isUpcast(candidateType: KotlinType, targetType: KotlinType): Boolean {
if (!typeChecker.isSubtypeOf(candidateType, targetType)) return false if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(candidateType, targetType)) return false
if (candidateType.isFunctionType && targetType.isFunctionType) { if (candidateType.isFunctionType && targetType.isFunctionType) {
return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.resolve.scopes.MemberScope; import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import org.jetbrains.kotlin.utils.DFS; import org.jetbrains.kotlin.utils.DFS;
@@ -305,7 +304,7 @@ public class CommonSupertypes {
} }
if (ins != null) { if (ins != null) {
assert !ins.isEmpty() : "In projections is empty for parameter " + parameterDescriptor + ", type projections " + typeProjections; assert !ins.isEmpty() : "In projections is empty for parameter " + parameterDescriptor + ", type projections " + typeProjections;
KotlinType intersection = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, ins); KotlinType intersection = TypeIntersector.intersectTypes(ins);
if (intersection == null) { if (intersection == null) {
return TypeUtils.makeStarProjection(parameterDescriptor); return TypeUtils.makeStarProjection(parameterDescriptor);
} }
@@ -37,11 +37,11 @@ import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt.getB
public class TypeIntersector { public class TypeIntersector {
public static boolean isIntersectionEmpty(@NotNull KotlinType typeA, @NotNull KotlinType typeB) { public static boolean isIntersectionEmpty(@NotNull KotlinType typeA, @NotNull KotlinType typeB) {
return intersectTypes(KotlinTypeChecker.DEFAULT, new LinkedHashSet<>(Arrays.asList(typeA, typeB))) == null; return intersectTypes(new LinkedHashSet<>(Arrays.asList(typeA, typeB))) == null;
} }
@Nullable @Nullable
public static KotlinType intersectTypes(@NotNull KotlinTypeChecker typeChecker, @NotNull Collection<KotlinType> types) { public static KotlinType intersectTypes(@NotNull Collection<KotlinType> types) {
assert !types.isEmpty() : "Attempting to intersect empty collection of types, this case should be dealt with on the call site."; assert !types.isEmpty() : "Attempting to intersect empty collection of types, this case should be dealt with on the call site.";
if (types.size() == 1) { if (types.size() == 1) {
@@ -72,6 +72,7 @@ public class TypeIntersector {
return ErrorUtils.createErrorType("Intersection of error types: " + types); return ErrorUtils.createErrorType("Intersection of error types: " + types);
} }
KotlinTypeChecker typeChecker = KotlinTypeChecker.DEFAULT;
// Now we remove types that have subtypes in the list // Now we remove types that have subtypes in the list
List<KotlinType> resultingTypes = new ArrayList<>(); List<KotlinType> resultingTypes = new ArrayList<>();
outer: outer:
@@ -151,7 +152,7 @@ public class TypeIntersector {
public static KotlinType getUpperBoundsAsType(@NotNull TypeParameterDescriptor descriptor) { public static KotlinType getUpperBoundsAsType(@NotNull TypeParameterDescriptor descriptor) {
List<KotlinType> upperBounds = descriptor.getUpperBounds(); List<KotlinType> upperBounds = descriptor.getUpperBounds();
assert !upperBounds.isEmpty() : "Upper bound list is empty: " + descriptor; assert !upperBounds.isEmpty() : "Upper bound list is empty: " + descriptor;
KotlinType upperBoundsAsType = intersectTypes(KotlinTypeChecker.DEFAULT, upperBounds); KotlinType upperBoundsAsType = intersectTypes(upperBounds);
return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(descriptor).getNothingType(); return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(descriptor).getNothingType();
} }
@@ -378,13 +378,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return; return;
} }
KotlinTypeChecker typeChecker = KotlinTypeChecker.DEFAULT; if (CastDiagnosticsUtil.INSTANCE.castIsUseless(expression, context, targetType, actualType)) {
if (CastDiagnosticsUtil.INSTANCE.castIsUseless(expression, context, targetType, actualType, typeChecker)) {
context.trace.report(USELESS_CAST.on(expression)); context.trace.report(USELESS_CAST.on(expression));
return; return;
} }
if (CastDiagnosticsUtil.isCastErased(actualType, targetType, typeChecker)) { if (CastDiagnosticsUtil.isCastErased(actualType, targetType, KotlinTypeChecker.DEFAULT)) {
context.trace.report(UNCHECKED_CAST.on(expression, actualType, targetType)); context.trace.report(UNCHECKED_CAST.on(expression, actualType, targetType));
} }
} }
@@ -462,7 +462,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
if (subjectType.containsError() || targetType.containsError()) return if (subjectType.containsError() || targetType.containsError()) return
val possibleTypes = DataFlowAnalyzer.getAllPossibleTypes(subjectType, context, subjectDataFlowValue) val possibleTypes = DataFlowAnalyzer.getAllPossibleTypes(subjectType, context, subjectDataFlowValue)
if (CastDiagnosticsUtil.isRefinementUseless(possibleTypes, targetType, KotlinTypeChecker.DEFAULT, false)) { if (CastDiagnosticsUtil.isRefinementUseless(possibleTypes, targetType, false)) {
context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated)) context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated))
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -509,7 +509,7 @@ public class KotlinTypeCheckerTest extends KotlinTestWithEnvironment {
for (String type : types) { for (String type : types) {
typesToIntersect.add(makeType(type)); typesToIntersect.add(makeType(type));
} }
KotlinType result = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, typesToIntersect); KotlinType result = TypeIntersector.intersectTypes(typesToIntersect);
// assertNotNull("Intersection is null for " + typesToIntersect, result); // assertNotNull("Intersection is null for " + typesToIntersect, result);
assertEquals(makeType(expected), result); assertEquals(makeType(expected), result);
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2016 JetBrains s.r.o. * Copyright 2010-2017 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -255,7 +255,7 @@ private fun KtNamedDeclaration.guessType(context: BindingContext): Array<KotlinT
if (expectedTypes.isEmpty() || expectedTypes.any { expectedType -> ErrorUtils.containsErrorType(expectedType) }) { if (expectedTypes.isEmpty() || expectedTypes.any { expectedType -> ErrorUtils.containsErrorType(expectedType) }) {
return arrayOf() return arrayOf()
} }
val theType = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, expectedTypes) val theType = TypeIntersector.intersectTypes(expectedTypes)
return if (theType != null) { return if (theType != null) {
arrayOf(theType) arrayOf(theType)
} }
@@ -66,7 +66,6 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.DFS.* import org.jetbrains.kotlin.utils.DFS.*
@@ -514,7 +513,7 @@ internal class MutableParameter(
private val defaultType: KotlinType by lazy { private val defaultType: KotlinType by lazy {
writable = false writable = false
if (defaultTypes.isNotEmpty()) { if (defaultTypes.isNotEmpty()) {
TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, defaultTypes)!! TypeIntersector.intersectTypes(defaultTypes)!!
} }
else originalType else originalType
} }