Refactoring. Move specificity relations into TypeSpecificityComparator component.

This commit is contained in:
Stanislav Erokhin
2016-04-28 15:15:38 +03:00
parent 921eb8402c
commit 8c2d68fff0
14 changed files with 124 additions and 61 deletions
@@ -0,0 +1,46 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.flexibility
import org.jetbrains.kotlin.types.isFlexible
object JvmTypeSpecificityComparator : TypeSpecificityComparator {
override fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType): Boolean {
if (!specific.isFlexible() || general.isFlexible()) return false
// general is inflexible
val flexibility = specific.flexibility()
// For primitive types we have to take care of the case when there are two overloaded methods like
// foo(int) and foo(Integer)
// if we do not discriminate one of them, any call to foo(kotlin.Int) will result in overload resolution ambiguity
// so, for such cases, we discriminate Integer in favour of int
if (!KotlinBuiltIns.isPrimitiveType(general) || !KotlinBuiltIns.isPrimitiveType(flexibility.lowerBound)) {
return false
}
// Int? >< Int!
if (general.isMarkedNullable) return false
// Int! lessSpecific Int
return true
}
}
@@ -18,11 +18,13 @@ package org.jetbrains.kotlin.resolve.jvm.platform
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.useImpl
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.jvm.RuntimeAssertionsTypeChecker
import org.jetbrains.kotlin.load.kotlin.JavaAnnotationCallChecker
import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeFunChecker
import org.jetbrains.kotlin.resolve.PlatformConfigurator
import org.jetbrains.kotlin.resolve.jvm.JvmOverloadFilter
import org.jetbrains.kotlin.resolve.jvm.JvmTypeSpecificityComparator
import org.jetbrains.kotlin.resolve.jvm.checkers.*
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
import org.jetbrains.kotlin.types.DynamicTypesSettings
@@ -79,5 +81,6 @@ object JvmPlatformConfigurator : PlatformConfigurator(
container.useImpl<ReflectionAPICallChecker>()
container.useImpl<JavaSyntheticScopes>()
container.useInstance(JvmTypeSpecificityComparator)
}
}
@@ -21,17 +21,14 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
import org.jetbrains.kotlin.resolve.calls.results.SpecificityComparisonCallbacks
import org.jetbrains.kotlin.resolve.calls.results.isSignatureNotLessSpecific
import org.jetbrains.kotlin.resolve.calls.results.varargParameterPosition
import org.jetbrains.kotlin.resolve.calls.results.*
import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.singletonOrEmptyList
class OverloadChecker {
class OverloadChecker(val specificityComparator: TypeSpecificityComparator) {
/**
* Does not check names.
*/
@@ -64,8 +61,8 @@ class OverloadChecker {
val aSignature = FlatSignature.createFromCallableDescriptor(a)
val bSignature = FlatSignature.createFromCallableDescriptor(b)
val aIsNotLessSpecificThanB = isSignatureNotLessSpecific(aSignature, bSignature, OverloadabilitySpecificityCallbacks)
val bIsNotLessSpecificThanA = isSignatureNotLessSpecific(bSignature, aSignature, OverloadabilitySpecificityCallbacks)
val aIsNotLessSpecificThanB = isSignatureNotLessSpecific(aSignature, bSignature, OverloadabilitySpecificityCallbacks, specificityComparator)
val bIsNotLessSpecificThanA = isSignatureNotLessSpecific(bSignature, aSignature, OverloadabilitySpecificityCallbacks, specificityComparator)
return !(aIsNotLessSpecificThanB && bIsNotLessSpecificThanA)
}
@@ -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.
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.ModuleParameters
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.checkers.*
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.resolve.validation.DeprecatedSymbolValidator
import org.jetbrains.kotlin.resolve.validation.InfixValidator
@@ -50,6 +51,7 @@ abstract class TargetPlatform(
override fun configure(container: StorageComponentContainer) {
super.configure(container)
container.useInstance(SyntheticScopes.Empty)
container.useInstance(TypeSpecificityComparator.NONE)
}
}
}
@@ -20,8 +20,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.CallHandle
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.valueParameterPosition
import org.jetbrains.kotlin.types.Flexibility
import org.jetbrains.kotlin.types.Flexibility.SpecificityRelation
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
@@ -31,10 +29,19 @@ interface SpecificityComparisonCallbacks {
fun isNonSubtypeNotLessSpecific(specific: KotlinType, general: KotlinType): Boolean
}
interface TypeSpecificityComparator {
fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType): Boolean
object NONE: TypeSpecificityComparator {
override fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType) = false
}
}
fun <T> isSignatureNotLessSpecific(
specific: FlatSignature<T>,
general: FlatSignature<T>,
callbacks: SpecificityComparisonCallbacks,
specificityComparator: TypeSpecificityComparator,
callHandle: CallHandle = CallHandle.NONE
): Boolean {
if (specific.hasExtensionReceiver != general.hasExtensionReceiver) return false
@@ -48,7 +55,7 @@ fun <T> isSignatureNotLessSpecific(
for ((specificType, generalType) in specific.valueParameterTypes.zip(general.valueParameterTypes)) {
if (specificType == null || generalType == null) continue
if (isDefinitelyLessSpecificByTypeSpecificity(specificType, generalType)) {
if (specificityComparator.isDefinitelyLessSpecific(specificType, generalType)) {
return false
}
@@ -69,13 +76,3 @@ fun <T> isSignatureNotLessSpecific(
val constraintSystem = constraintSystemBuilder.build()
return !constraintSystem.status.hasContradiction()
}
private fun KotlinType.getSpecificityRelationTo(otherType: KotlinType) =
this.getCapability(Flexibility::class.java)?.getSpecificityRelationTo(otherType) ?: Flexibility.SpecificityRelation.DONT_KNOW
private fun isDefinitelyLessSpecificByTypeSpecificity(specific: KotlinType, general: KotlinType): Boolean {
val sThanG = specific.getSpecificityRelationTo(general)
val gThanS = general.getSpecificityRelationTo(specific)
return sThanG == SpecificityRelation.LESS_SPECIFIC &&
gThanS != SpecificityRelation.LESS_SPECIFIC
}
@@ -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.
@@ -32,7 +32,10 @@ import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
class OverloadingConflictResolver(
private val builtIns: KotlinBuiltIns,
private val specificityComparator: TypeSpecificityComparator
) {
fun <D : CallableDescriptor> findMaximallySpecific(
candidates: Set<MutableResolvedCall<D>>,
@@ -157,7 +160,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
if (isGeneric1 && isGeneric2) return false
}
return isSignatureNotLessSpecific(call1, call2, SpecificityComparisonWithNumerics, call1.callHandle())
return isSignatureNotLessSpecific(call1, call2, SpecificityComparisonWithNumerics, specificityComparator, call1.callHandle())
}
private val SpecificityComparisonWithNumerics = object : SpecificityComparisonCallbacks {
@@ -243,7 +246,7 @@ class OverloadingConflictResolver(private val builtIns: KotlinBuiltIns) {
val fSignature = FlatSignature.createFromCallableDescriptor(f)
val gSignature = FlatSignature.createFromCallableDescriptor(g)
return isSignatureNotLessSpecific(fSignature, gSignature, SpecificityComparisonWithNumerics)
return isSignatureNotLessSpecific(fSignature, gSignature, SpecificityComparisonWithNumerics, specificityComparator)
}
private fun isNotLessSpecificCallableReference(f: CallableDescriptor, g: CallableDescriptor): Boolean =
@@ -82,7 +82,10 @@ public class ExpressionTypingUtils {
@NotNull
public static LexicalWritableScope newWritableScopeImpl(
@NotNull ExpressionTypingContext context, @NotNull LexicalScopeKind scopeKind, @NotNull OverloadChecker overloadChecker) {
@NotNull ExpressionTypingContext context,
@NotNull LexicalScopeKind scopeKind,
@NotNull OverloadChecker overloadChecker
) {
return new LexicalWritableScope(context.scope, context.scope.getOwnerDescriptor(), false, null,
new TraceBasedLocalRedeclarationChecker(context.trace, overloadChecker), scopeKind);
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.psi.KtPsiFactoryKt;
import org.jetbrains.kotlin.resolve.FunctionDescriptorResolver;
import org.jetbrains.kotlin.resolve.OverloadChecker;
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.test.ConfigurationKind;
@@ -34,7 +35,7 @@ import org.jetbrains.kotlin.tests.di.InjectionKt;
public class KotlinOverloadTest extends KotlinTestWithEnvironment {
private final ModuleDescriptor root = KotlinTestUtils.createEmptyModule("<test_root>");
private FunctionDescriptorResolver functionDescriptorResolver;
private final OverloadChecker overloadChecker = new OverloadChecker();
private final OverloadChecker overloadChecker = new OverloadChecker(TypeSpecificityComparator.NONE.INSTANCE);
@Override
protected KotlinCoreEnvironment createEnvironment() {
@@ -155,8 +156,6 @@ public class KotlinOverloadTest extends KotlinTestWithEnvironment {
FunctionDescriptor a = makeFunction(funA);
FunctionDescriptor b = makeFunction(funB);
boolean aOverloadableWithB = overloadChecker.isOverloadable(a, b);
assertEquals(expectedIsError, !aOverloadableWithB);
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactoryKt;
import org.jetbrains.kotlin.psi.KtTypeReference;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator;
import org.jetbrains.kotlin.resolve.lazy.LazyResolveTestUtil;
import org.jetbrains.kotlin.resolve.scopes.*;
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
@@ -90,7 +91,8 @@ public class TypeSubstitutorTest extends KotlinTestWithEnvironment {
LexicalScope topLevelScope = trace.get(BindingContext.LEXICAL_SCOPE, jetFile);
final ClassifierDescriptor contextClass = ScopeUtilsKt.findClassifier(topLevelScope, Name.identifier("___Context"), NoLookupLocation.FROM_TEST);
assert contextClass instanceof ClassDescriptor;
LocalRedeclarationChecker redeclarationChecker = new ThrowingLocalRedeclarationChecker(new OverloadChecker());
LocalRedeclarationChecker redeclarationChecker = new ThrowingLocalRedeclarationChecker(new OverloadChecker(
TypeSpecificityComparator.NONE.INSTANCE));
LexicalScope typeParameters = new LexicalScopeImpl(topLevelScope, module, false, null, LexicalScopeKind.SYNTHETIC,
redeclarationChecker,
new Function1<LexicalScopeImpl.InitializeHandler, Unit>() {
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.load.java.lazy.types
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -34,9 +33,7 @@ import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Flexibility.SpecificityRelation
import org.jetbrains.kotlin.types.Variance.*
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
@@ -315,21 +312,6 @@ class LazyJavaTypeResolver(
else create(replacement, TypeUtils.makeNullable(replacement))
}
override fun getSpecificityRelationTo(otherType: KotlinType): SpecificityRelation {
// For primitive types we have to take care of the case when there are two overloaded methods like
// foo(int) and foo(Integer)
// if we do not discriminate one of them, any call to foo(kotlin.Int) will result in overload resolution ambiguity
// so, for such cases, we discriminate Integer in favour of int
if (!KotlinBuiltIns.isPrimitiveType(otherType) || !KotlinBuiltIns.isPrimitiveType(lowerBound)) {
return SpecificityRelation.DONT_KNOW
}
// Int! >< Int?
if (otherType.isFlexible()) return SpecificityRelation.DONT_KNOW
// Int? >< Int!
if (otherType.isMarkedNullable) return SpecificityRelation.DONT_KNOW
// Int! lessSpecific Int
return SpecificityRelation.LESS_SPECIFIC
}
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.types
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.types.Flexibility.SpecificityRelation
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.builtIns
@@ -53,10 +52,6 @@ object DynamicTypeFactory : FlexibleTypeFactory {
override val delegateType: KotlinType get() = upperBound
override fun getSpecificityRelationTo(otherType: KotlinType): SpecificityRelation {
return if (!otherType.isDynamic()) SpecificityRelation.LESS_SPECIFIC else SpecificityRelation.DONT_KNOW
}
override fun makeNullableAsSpecified(nullable: Boolean): KotlinType {
// Nullability has no effect on dynamics
return createDynamicType(delegateType.builtIns)
@@ -49,13 +49,6 @@ interface Flexibility : TypeCapability, SubtypingRepresentatives {
fun makeNullableAsSpecified(nullable: Boolean): KotlinType
enum class SpecificityRelation {
LESS_SPECIFIC,
MORE_SPECIFIC,
DONT_KNOW
}
fun getSpecificityRelationTo(otherType: KotlinType): SpecificityRelation
}
fun KotlinType.isFlexible(): Boolean = this.getCapability(Flexibility::class.java) != null
@@ -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.
@@ -43,5 +43,6 @@ object JsPlatformConfigurator : PlatformConfigurator(
container.useImpl<JsCallChecker>()
container.useInstance(SyntheticScopes.Empty)
container.useInstance(JsTypeSpecificityComparator)
}
}
@@ -0,0 +1,40 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.resolve
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.isFlexible
object JsTypeSpecificityComparator: TypeSpecificityComparator {
private fun checkOnlyDynamicFlexibleType(type: KotlinType) {
if (type.isFlexible()) {
assert(type.isDynamic()) {
"Unexpected flexible type in Js: $type"
}
}
}
override fun isDefinitelyLessSpecific(specific: KotlinType, general: KotlinType): Boolean {
checkOnlyDynamicFlexibleType(specific)
checkOnlyDynamicFlexibleType(general)
return specific.isDynamic() && !general.isDynamic()
}
}