checkSupertypesForConsistency() moved to declarations checker
This commit is contained in:
@@ -16,20 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve;
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.types.DeferredType;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
import org.jetbrains.jet.lexer.JetKeywordToken;
|
import org.jetbrains.jet.lexer.JetKeywordToken;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||||
import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
|
import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
|
||||||
@@ -60,6 +60,8 @@ public class DeclarationsChecker {
|
|||||||
checkObject((JetObjectDeclaration) classOrObject);
|
checkObject((JetObjectDeclaration) classOrObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkSupertypesForConsistency(classDescriptor);
|
||||||
|
|
||||||
modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
|
modifiersChecker.checkModifiersForDeclaration(classOrObject, classDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +95,83 @@ public class DeclarationsChecker {
|
|||||||
trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration));
|
trace.report(ILLEGAL_ANNOTATION_KEYWORD.on(declaration));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkSupertypesForConsistency(@NotNull ClassDescriptor classDescriptor) {
|
||||||
|
Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
|
||||||
|
.buildDeepSubstitutionMultimap(classDescriptor.getDefaultType());
|
||||||
|
for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
|
||||||
|
Collection<TypeProjection> projections = entry.getValue();
|
||||||
|
if (projections.size() > 1) {
|
||||||
|
TypeConstructor typeConstructor = entry.getKey();
|
||||||
|
DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
|
||||||
|
assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
|
||||||
|
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
|
||||||
|
|
||||||
|
// Immediate arguments of supertypes cannot be projected
|
||||||
|
Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
|
||||||
|
for (TypeProjection projection : projections) {
|
||||||
|
conflictingTypes.add(projection.getType());
|
||||||
|
}
|
||||||
|
switch (typeParameterDescriptor.getVariance()) {
|
||||||
|
case INVARIANT:
|
||||||
|
// Leave conflicting types as is
|
||||||
|
break;
|
||||||
|
case IN_VARIANCE:
|
||||||
|
// Filter out those who have supertypes in this set (common supertype)
|
||||||
|
Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
|
||||||
|
break;
|
||||||
|
case OUT_VARIANCE:
|
||||||
|
// Filter out those who have subtypes in this set (common subtype)
|
||||||
|
Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conflictingTypes.size() > 1) {
|
||||||
|
DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
|
||||||
|
assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
|
||||||
|
JetClassOrObject psiElement = (JetClassOrObject) BindingContextUtils
|
||||||
|
.classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
|
||||||
|
JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
|
||||||
|
assert delegationSpecifierList != null;
|
||||||
|
// trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
|
||||||
|
trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
|
||||||
|
.on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
|
||||||
|
conflictingTypes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Filter {
|
||||||
|
REMOVE_IF_SUBTYPE_IN_THE_SET {
|
||||||
|
@Override
|
||||||
|
public boolean removeNeeded(JetType subject, JetType other) {
|
||||||
|
return JetTypeChecker.INSTANCE.isSubtypeOf(other, subject);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
REMOVE_IF_SUPERTYPE_IN_THE_SET {
|
||||||
|
@Override
|
||||||
|
public boolean removeNeeded(JetType subject, JetType other) {
|
||||||
|
return JetTypeChecker.INSTANCE.isSubtypeOf(subject, other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void proceed(Set<JetType> conflictingTypes) {
|
||||||
|
for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
|
||||||
|
JetType type = iterator.next();
|
||||||
|
for (JetType otherType : conflictingTypes) {
|
||||||
|
boolean subtypeOf = removeNeeded(type, otherType);
|
||||||
|
if (type != otherType && subtypeOf) {
|
||||||
|
iterator.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean removeNeeded(JetType subject, JetType other);
|
||||||
|
}
|
||||||
|
|
||||||
private void checkObject(JetObjectDeclaration declaration) {
|
private void checkObject(JetObjectDeclaration declaration) {
|
||||||
reportErrorIfHasIllegalModifier(declaration);
|
reportErrorIfHasIllegalModifier(declaration);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.jet.lang.resolve;
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||||
@@ -29,9 +28,11 @@ import org.jetbrains.jet.lang.psi.*;
|
|||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.name.SpecialNames;
|
import org.jetbrains.jet.lang.resolve.name.SpecialNames;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.*;
|
import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||||
|
import org.jetbrains.jet.lang.resolve.scopes.WriteThroughScope;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||||
import org.jetbrains.jet.utils.DFS;
|
import org.jetbrains.jet.utils.DFS;
|
||||||
|
|
||||||
@@ -137,9 +138,6 @@ public class TypeHierarchyResolver {
|
|||||||
|
|
||||||
// At this point, there are no loops in the type hierarchy
|
// At this point, there are no loops in the type hierarchy
|
||||||
|
|
||||||
checkSupertypesForConsistency(c);
|
|
||||||
// computeSuperclasses();
|
|
||||||
|
|
||||||
checkTypesInClassHeaders(c); // Check bounds in the types used in generic bounds and supertype lists
|
checkTypesInClassHeaders(c); // Check bounds in the types used in generic bounds and supertype lists
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,84 +331,6 @@ public class TypeHierarchyResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSupertypesForConsistency(@NotNull TopDownAnalysisContext c) {
|
|
||||||
for (MutableClassDescriptorLite mutableClassDescriptor : c.getClassesTopologicalOrder()) {
|
|
||||||
Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
|
|
||||||
.buildDeepSubstitutionMultimap(mutableClassDescriptor.getDefaultType());
|
|
||||||
for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
|
|
||||||
Collection<TypeProjection> projections = entry.getValue();
|
|
||||||
if (projections.size() > 1) {
|
|
||||||
TypeConstructor typeConstructor = entry.getKey();
|
|
||||||
DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
|
|
||||||
assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
|
|
||||||
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
|
|
||||||
|
|
||||||
// Immediate arguments of supertypes cannot be projected
|
|
||||||
Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
|
|
||||||
for (TypeProjection projection : projections) {
|
|
||||||
conflictingTypes.add(projection.getType());
|
|
||||||
}
|
|
||||||
switch (typeParameterDescriptor.getVariance()) {
|
|
||||||
case INVARIANT:
|
|
||||||
// Leave conflicting types as is
|
|
||||||
break;
|
|
||||||
case IN_VARIANCE:
|
|
||||||
// Filter out those who have supertypes in this set (common supertype)
|
|
||||||
Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
|
|
||||||
break;
|
|
||||||
case OUT_VARIANCE:
|
|
||||||
// Filter out those who have subtypes in this set (common subtype)
|
|
||||||
Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conflictingTypes.size() > 1) {
|
|
||||||
DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
|
|
||||||
assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
|
|
||||||
JetClassOrObject psiElement = (JetClassOrObject) BindingContextUtils
|
|
||||||
.classDescriptorToDeclaration(trace.getBindingContext(), mutableClassDescriptor);
|
|
||||||
JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
|
|
||||||
assert delegationSpecifierList != null;
|
|
||||||
// trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
|
|
||||||
trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
|
|
||||||
.on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
|
|
||||||
conflictingTypes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum Filter {
|
|
||||||
REMOVE_IF_SUBTYPE_IN_THE_SET {
|
|
||||||
@Override
|
|
||||||
public boolean removeNeeded(JetType subject, JetType other) {
|
|
||||||
return JetTypeChecker.INSTANCE.isSubtypeOf(other, subject);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
REMOVE_IF_SUPERTYPE_IN_THE_SET {
|
|
||||||
@Override
|
|
||||||
public boolean removeNeeded(JetType subject, JetType other) {
|
|
||||||
return JetTypeChecker.INSTANCE.isSubtypeOf(subject, other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private void proceed(Set<JetType> conflictingTypes) {
|
|
||||||
for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
|
|
||||||
JetType type = iterator.next();
|
|
||||||
for (JetType otherType : conflictingTypes) {
|
|
||||||
boolean subtypeOf = removeNeeded(type, otherType);
|
|
||||||
if (type != otherType && subtypeOf) {
|
|
||||||
iterator.remove();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract boolean removeNeeded(JetType subject, JetType other);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkTypesInClassHeaders(@NotNull TopDownAnalysisContext c) {
|
private void checkTypesInClassHeaders(@NotNull TopDownAnalysisContext c) {
|
||||||
for (JetClassOrObject classOrObject : c.getClasses().keySet()) {
|
for (JetClassOrObject classOrObject : c.getClasses().keySet()) {
|
||||||
for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
|
for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
|
||||||
|
|||||||
+7
-3
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.*;
|
import org.jetbrains.jet.lang.resolve.scopes.*;
|
||||||
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -69,9 +70,12 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement
|
|||||||
|
|
||||||
constructors.add(constructorDescriptor);
|
constructors.add(constructorDescriptor);
|
||||||
|
|
||||||
if (defaultType.isComputed()) {
|
((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(new DelegatingType() {
|
||||||
((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(getDefaultType());
|
@Override
|
||||||
}
|
protected JetType getDelegate() {
|
||||||
|
return getDefaultType();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (constructorDescriptor.isPrimary()) {
|
if (constructorDescriptor.isPrimary()) {
|
||||||
setUpScopeForInitializers(constructorDescriptor);
|
setUpScopeForInitializers(constructorDescriptor);
|
||||||
|
|||||||
Reference in New Issue
Block a user