TypeConstructor's equality for classes relies on FqNames

This is needed because different modules/libraries may define classes with the same FqNames, which may be identical or slightly different.
 Such classes must be considered equal, because your dependencies may rely on different packagings of the same codebase, and the classes there will be distinct though identical
  (think intellij-core vs idea-full).
This commit is contained in:
Andrey Breslav
2014-05-21 18:24:03 +04:00
parent f714382bd8
commit a66f44e4f5
25 changed files with 599 additions and 15 deletions
@@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.descriptors.impl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -49,7 +48,7 @@ public class ClassDescriptorImpl extends ClassDescriptorBase {
super(LockBasedStorageManager.NO_LOCKS, containingDeclaration, name);
this.modality = modality;
this.typeConstructor = new TypeConstructorImpl(this, Annotations.EMPTY, false, getName().asString(),
this.typeConstructor = TypeConstructorImpl.createForClass(this, Annotations.EMPTY, false, getName().asString(),
Collections.<TypeParameterDescriptor>emptyList(), supertypes);
}
@@ -78,7 +78,7 @@ public class EnumEntrySyntheticClassDescriptor extends ClassDescriptorBase {
this.kind = kind;
this.typeConstructor =
new TypeConstructorImpl(this, getAnnotations(), true, "enum entry", Collections.<TypeParameterDescriptor>emptyList(),
TypeConstructorImpl.createForClass(this, getAnnotations(), true, "enum entry", Collections.<TypeParameterDescriptor>emptyList(),
Collections.singleton(supertype));
this.scope = new EnumEntryScope(storageManager);
@@ -72,7 +72,7 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
supertypes.add(substitutor.substitute(supertype, Variance.INVARIANT));
}
typeConstructor = new TypeConstructorImpl(
typeConstructor = TypeConstructorImpl.createForClass(
this,
originalTypeConstructor.getAnnotations(),
originalTypeConstructor.isFinal(),
@@ -233,7 +233,7 @@ public class MutableClassDescriptor extends ClassDescriptorBase implements Class
public void createTypeConstructor() {
assert typeConstructor == null : typeConstructor;
this.typeConstructor = new TypeConstructorImpl(
this.typeConstructor = TypeConstructorImpl.createForClass(
this,
Annotations.EMPTY, // TODO : pass annotations from the class?
!getModality().isOverridable(),
@@ -77,7 +77,7 @@ public class TypeParameterDescriptorImpl extends AbstractTypeParameterDescriptor
@Override
protected TypeConstructor createTypeConstructor() {
// TODO: Should we actually pass the annotations on to the type constructor?
return new TypeConstructorImpl(
return TypeConstructorImpl.createForTypeParameter(
this,
getAnnotations(),
false,
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2014 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.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
public abstract class AbstractClassTypeConstructor implements TypeConstructor {
@Override
public final int hashCode() {
return hashCode(this);
}
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object obj) {
return equals(this, obj);
}
public static boolean equals(@NotNull TypeConstructor me, Object other) {
if (!(other instanceof TypeConstructor)) return false;
ClassifierDescriptor myDescriptor = me.getDeclarationDescriptor();
ClassifierDescriptor otherDescriptor = ((TypeConstructor) other).getDeclarationDescriptor();
if (myDescriptor == otherDescriptor) return true;
if (myDescriptor instanceof ClassDescriptor && otherDescriptor instanceof ClassDescriptor) {
FqNameUnsafe otherFqName = DescriptorUtils.getFqName(otherDescriptor);
FqNameUnsafe myFqName = DescriptorUtils.getFqName(myDescriptor);
return myFqName.equals(otherFqName);
}
return false;
}
public static int hashCode(@NotNull TypeConstructor me) {
if (me.getDeclarationDescriptor() instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) me.getDeclarationDescriptor();
return DescriptorUtils.getFqName(classDescriptor).hashCode();
}
return System.identityHashCode(me);
}
}
@@ -346,7 +346,7 @@ public class ErrorUtils {
@NotNull
private static TypeConstructor createErrorTypeConstructorWithCustomDebugName(@NotNull String debugName) {
return new TypeConstructorImpl(ERROR_CLASS, Annotations.EMPTY, false, debugName,
return TypeConstructorImpl.createForClass(ERROR_CLASS, Annotations.EMPTY, false, debugName,
Collections.<TypeParameterDescriptorImpl>emptyList(),
Collections.singleton(KotlinBuiltIns.getInstance().getAnyType()));
}
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotatedImpl;
@@ -28,16 +29,61 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class TypeConstructorImpl extends AnnotatedImpl implements TypeConstructor {
public abstract class TypeConstructorImpl extends AnnotatedImpl implements TypeConstructor {
@NotNull
public static TypeConstructorImpl createForClass(
@NotNull ClassDescriptor classDescriptor,
@NotNull Annotations annotations,
boolean isFinal,
@NotNull String debugName,
@NotNull List<? extends TypeParameterDescriptor> parameters,
@NotNull Collection<JetType> supertypes
) {
return new TypeConstructorImpl(classDescriptor, annotations, isFinal, debugName, parameters, supertypes) {
@Override
public int hashCode() {
return AbstractClassTypeConstructor.hashCode(this);
}
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object obj) {
return AbstractClassTypeConstructor.equals(this, obj);
}
};
}
@NotNull
public static TypeConstructorImpl createForTypeParameter(
@NotNull TypeParameterDescriptor typeParameterDescriptor,
@NotNull Annotations annotations,
boolean isFinal,
@NotNull String debugName,
@NotNull List<? extends TypeParameterDescriptor> parameters,
@NotNull Collection<JetType> supertypes
) {
return new TypeConstructorImpl(typeParameterDescriptor, annotations, isFinal, debugName, parameters, supertypes) {
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public boolean equals(Object obj) {
return this == obj;
}
};
}
private final List<TypeParameterDescriptor> parameters;
private final Collection<JetType> supertypes;
private final String debugName;
private final boolean isFinal;
@Nullable
private final ClassifierDescriptor classifierDescriptor;
public TypeConstructorImpl(
private TypeConstructorImpl(
@Nullable ClassifierDescriptor classifierDescriptor,
@NotNull Annotations annotations,
boolean isFinal,
@@ -84,4 +130,10 @@ public class TypeConstructorImpl extends AnnotatedImpl implements TypeConstructo
public ClassifierDescriptor getDeclarationDescriptor() {
return classifierDescriptor;
}
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
}
@@ -181,11 +181,12 @@ public class TypeCheckingProcedure {
List<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments();
if (subArguments.size() != superArguments.size()) return false;
List<TypeParameterDescriptor> parameters = constructor.getParameters();
for (int i = 0; i < parameters.size(); i++) {
TypeParameterDescriptor parameter = parameters.get(i);
TypeProjection subArgument = subArguments.get(i);
JetType subIn = getInType(parameter, subArgument);
JetType subOut = getOutType(parameter, subArgument);