From 0352bdbca568bbbdd9c44809e54c17443a7b4922 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 21 Jun 2017 15:17:26 +0300 Subject: [PATCH] Optimize and improve AbstractClassTypeConstructor.equals Instead of computing and comparing FQ names, compare simple names of classes and theirs containers. This code was responsible for creation of about 10% of FqNameUnsafe instances during compilation of "core" modules. Also make the check more strict: previously, a class "c" declared in package "a.b" would be considered equal to a class "c" declared in class "b" in package "a". Because JVM type descriptors of such classes are different, this behavior was suspicious and might have lead to error at runtime. Now, we require the number of containing classes of the given two classes also to be the same --- .../types/AbstractClassTypeConstructor.java | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java index 238df26c26b..508be0e302e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/AbstractClassTypeConstructor.java @@ -18,9 +18,7 @@ package org.jetbrains.kotlin.types; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; -import org.jetbrains.kotlin.descriptors.ClassDescriptor; -import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; @@ -63,7 +61,7 @@ public abstract class AbstractClassTypeConstructor extends AbstractTypeConstruct } @Override - public boolean equals(Object other) { + public final boolean equals(Object other) { if (!(other instanceof TypeConstructor)) return false; // performance optimization: getFqName is slow method @@ -86,14 +84,35 @@ public abstract class AbstractClassTypeConstructor extends AbstractTypeConstruct } if (myDescriptor instanceof ClassDescriptor && otherDescriptor instanceof ClassDescriptor) { - FqNameUnsafe otherFqName = DescriptorUtils.getFqName(otherDescriptor); - FqNameUnsafe myFqName = DescriptorUtils.getFqName(myDescriptor); - return myFqName.equals(otherFqName); + return areFqNamesEqual(((ClassDescriptor) myDescriptor), ((ClassDescriptor) otherDescriptor)); } return false; } + private static boolean areFqNamesEqual(ClassDescriptor first, ClassDescriptor second) { + if (!first.getName().equals(second.getName())) return false; + + DeclarationDescriptor a = first.getContainingDeclaration(); + DeclarationDescriptor b = second.getContainingDeclaration(); + while (a != null && b != null) { + if (a instanceof ModuleDescriptor) return b instanceof ModuleDescriptor; + if (b instanceof ModuleDescriptor) return false; + + if (a instanceof PackageFragmentDescriptor) { + return b instanceof PackageFragmentDescriptor && + ((PackageFragmentDescriptor) a).getFqName().equals(((PackageFragmentDescriptor) b).getFqName()); + } + if (b instanceof PackageFragmentDescriptor) return false; + + if (!a.getName().equals(b.getName())) return false; + + a = a.getContainingDeclaration(); + b = b.getContainingDeclaration(); + } + return true; + } + private static boolean hasMeaningfulFqName(@NotNull ClassifierDescriptor descriptor) { return !ErrorUtils.isError(descriptor) && !DescriptorUtils.isLocal(descriptor);