Merge branch 'master' of ssh://git.labs.intellij.net/jet
This commit is contained in:
@@ -175,4 +175,24 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
|
|||||||
return visitor.visitFunctionDescriptor(this, data);
|
return visitor.visitFunctionDescriptor(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public boolean equals(Object obj) {
|
||||||
|
// if (obj == null) return false;
|
||||||
|
// if (obj.getClass() != FunctionDescriptorImpl.class) return false;
|
||||||
|
// FunctionDescriptorImpl other = (FunctionDescriptorImpl) obj;
|
||||||
|
// if (!eq(this.getName(), other.getName())) return false;
|
||||||
|
// if (!eq(this.getContainingDeclaration(), other.getContainingDeclaration())) return false;
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static boolean eq(Object a, Object b) {
|
||||||
|
// if (a == null) return b == null;
|
||||||
|
// if (b == null) return false;
|
||||||
|
// return a.equals(b);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public int hashCode() {
|
||||||
|
// return super.hashCode(); // TODO
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
package org.jetbrains.jet.lang.descriptors;
|
package org.jetbrains.jet.lang.descriptors;
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import com.google.common.collect.HashBiMap;
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
@@ -112,125 +109,4 @@ public class FunctionDescriptorUtil {
|
|||||||
return parameterScope;
|
return parameterScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class OverrideCompatibilityInfo {
|
|
||||||
|
|
||||||
private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(false, "SUCCESS");
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo nameMismatch() {
|
|
||||||
return new OverrideCompatibilityInfo(true, "nameMismatch"); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo typeParameterNumberMismatch() {
|
|
||||||
return new OverrideCompatibilityInfo(true, "typeParameterNumberMismatch"); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo valueParameterNumberMismatch() {
|
|
||||||
return new OverrideCompatibilityInfo(true, "valueParameterNumberMismatch"); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo boundsMismatch(TypeParameterDescriptor superTypeParameter, TypeParameterDescriptor subTypeParameter) {
|
|
||||||
return new OverrideCompatibilityInfo(true, "boundsMismatch"); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo valueParameterTypeMismatch(ValueParameterDescriptor superValueParameter, ValueParameterDescriptor subValueParameter) {
|
|
||||||
return new OverrideCompatibilityInfo(true, "valueParameterTypeMismatch"); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo returnTypeMismatch(JetType substitutedSuperReturnType, JetType unsubstitutedSubReturnType) {
|
|
||||||
return new OverrideCompatibilityInfo(true, "returnTypeMismatch: " + unsubstitutedSubReturnType + " >< " + substitutedSuperReturnType); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo success() {
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private final boolean isError;
|
|
||||||
private final String message;
|
|
||||||
|
|
||||||
public OverrideCompatibilityInfo(boolean error, String message) {
|
|
||||||
isError = error;
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSuccess() {
|
|
||||||
return !isError;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static OverrideCompatibilityInfo isOverridableBy(@NotNull JetTypeChecker typeChecker, @NotNull FunctionDescriptor superFunction, @NotNull FunctionDescriptor subFunction) {
|
|
||||||
if (!superFunction.getName().equals(subFunction.getName())) {
|
|
||||||
return OverrideCompatibilityInfo.nameMismatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : Visibility
|
|
||||||
|
|
||||||
if (superFunction.getTypeParameters().size() != subFunction.getTypeParameters().size()) {
|
|
||||||
return OverrideCompatibilityInfo.typeParameterNumberMismatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (superFunction.getValueParameters().size() != subFunction.getValueParameters().size()) {
|
|
||||||
return OverrideCompatibilityInfo.valueParameterNumberMismatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TypeParameterDescriptor> superTypeParameters = superFunction.getTypeParameters();
|
|
||||||
List<TypeParameterDescriptor> subTypeParameters = subFunction.getTypeParameters();
|
|
||||||
|
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = Maps.newHashMap();
|
|
||||||
BiMap<TypeConstructor, TypeConstructor> axioms = HashBiMap.create();
|
|
||||||
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
|
||||||
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
|
||||||
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
|
||||||
substitutionContext.put(
|
|
||||||
superTypeParameter.getTypeConstructor(),
|
|
||||||
new TypeProjection(subTypeParameter.getDefaultType()));
|
|
||||||
axioms.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
|
||||||
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
|
||||||
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
|
||||||
|
|
||||||
|
|
||||||
if (!JetTypeImpl.equalTypes(superTypeParameter.getBoundsAsType(), subTypeParameter.getBoundsAsType(), axioms)) {
|
|
||||||
return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ValueParameterDescriptor> superValueParameters = superFunction.getValueParameters();
|
|
||||||
List<ValueParameterDescriptor> subValueParameters = subFunction.getValueParameters();
|
|
||||||
for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
|
|
||||||
ValueParameterDescriptor superValueParameter = superValueParameters.get(i);
|
|
||||||
ValueParameterDescriptor subValueParameter = subValueParameters.get(i);
|
|
||||||
|
|
||||||
if (!JetTypeImpl.equalTypes(superValueParameter.getOutType(), subValueParameter.getOutType(), axioms)) {
|
|
||||||
return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : Default values, varargs etc
|
|
||||||
|
|
||||||
TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitutionContext);
|
|
||||||
JetType substitutedSuperReturnType = typeSubstitutor.substitute(superFunction.getReturnType(), Variance.OUT_VARIANCE);
|
|
||||||
assert substitutedSuperReturnType != null;
|
|
||||||
if (!typeChecker.isSubtypeOf(subFunction.getReturnType(), substitutedSuperReturnType)) {
|
|
||||||
return OverrideCompatibilityInfo.returnTypeMismatch(substitutedSuperReturnType, subFunction.getReturnType());
|
|
||||||
}
|
|
||||||
|
|
||||||
return OverrideCompatibilityInfo.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.jet.lang.descriptors;
|
package org.jetbrains.jet.lang.descriptors;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
@@ -11,6 +12,7 @@ import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
|||||||
import org.jetbrains.jet.lang.types.Variance;
|
import org.jetbrains.jet.lang.types.Variance;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -21,6 +23,7 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
|
|||||||
private final Visibility visibility;
|
private final Visibility visibility;
|
||||||
private final boolean isVar;
|
private final boolean isVar;
|
||||||
private final ReceiverDescriptor receiver;
|
private final ReceiverDescriptor receiver;
|
||||||
|
private final Set<PropertyDescriptor> overriddenProperties = Sets.newLinkedHashSet();
|
||||||
private final List<TypeParameterDescriptor> typeParemeters = Lists.newArrayListWithCapacity(0);
|
private final List<TypeParameterDescriptor> typeParemeters = Lists.newArrayListWithCapacity(0);
|
||||||
private final PropertyDescriptor original;
|
private final PropertyDescriptor original;
|
||||||
private PropertyGetterDescriptor getter;
|
private PropertyGetterDescriptor getter;
|
||||||
@@ -156,4 +159,14 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
|
|||||||
public PropertyDescriptor getOriginal() {
|
public PropertyDescriptor getOriginal() {
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addOverriddenDescriptor(PropertyDescriptor overridden) {
|
||||||
|
overriddenProperties.add(overridden);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Set<? extends CallableDescriptor> getOverriddenDescriptors() {
|
||||||
|
return overriddenProperties;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class BodyResolver {
|
|||||||
|
|
||||||
|
|
||||||
public void resolveBehaviorDeclarationBodies() {
|
public void resolveBehaviorDeclarationBodies() {
|
||||||
bindOverrides();
|
// bindOverrides();
|
||||||
|
|
||||||
resolveDelegationSpecifierLists();
|
resolveDelegationSpecifierLists();
|
||||||
resolveClassAnnotations();
|
resolveClassAnnotations();
|
||||||
@@ -81,125 +81,9 @@ public class BodyResolver {
|
|||||||
|
|
||||||
checkIfPrimaryConstructorIsNecessary();
|
checkIfPrimaryConstructorIsNecessary();
|
||||||
|
|
||||||
checkOverrides();
|
// checkOverrides();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindOverrides() {
|
|
||||||
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
|
|
||||||
bindOverridesInAClass(entry.getValue());
|
|
||||||
}
|
|
||||||
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
|
|
||||||
bindOverridesInAClass(entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) {
|
|
||||||
|
|
||||||
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
|
|
||||||
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
|
|
||||||
FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype);
|
|
||||||
if (overridden != null) {
|
|
||||||
((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) {
|
|
||||||
FunctionGroup functionGroup = supertype.getMemberScope().getFunctionGroup(declaredFunction.getName());
|
|
||||||
for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) {
|
|
||||||
if (FunctionDescriptorUtil.isOverridableBy(context.getSemanticServices().getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) {
|
|
||||||
return functionDescriptor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkOverrides() {
|
|
||||||
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
|
|
||||||
checkOverridesInAClass(entry.getValue(), entry.getKey());
|
|
||||||
}
|
|
||||||
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
|
|
||||||
checkOverridesInAClass(entry.getValue(), entry.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
|
|
||||||
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
|
|
||||||
checkOverrideForFunction(declaredFunction);
|
|
||||||
}
|
|
||||||
if (classDescriptor.getModality() == Modality.ABSTRACT) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Set<FunctionDescriptor> allOverriddenFunctions = Sets.newHashSet();
|
|
||||||
Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors();
|
|
||||||
for (DeclarationDescriptor descriptor : allDescriptors) {
|
|
||||||
if (descriptor instanceof FunctionDescriptor) {
|
|
||||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
|
||||||
if (functionDescriptor.getModality() != Modality.ABSTRACT) {
|
|
||||||
for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
|
|
||||||
allOverriddenFunctions.add(overriddenDescriptor.getOriginal());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean foundError = false;
|
|
||||||
PsiElement nameIdentifier = null;
|
|
||||||
if (klass instanceof JetClass) {
|
|
||||||
nameIdentifier = ((JetClass) klass).getNameIdentifier();
|
|
||||||
}
|
|
||||||
else if (klass instanceof JetObjectDeclaration) {
|
|
||||||
nameIdentifier = ((JetObjectDeclaration) klass).getNameIdentifier();
|
|
||||||
}
|
|
||||||
for (DeclarationDescriptor descriptor : allDescriptors) {
|
|
||||||
if (descriptor instanceof FunctionDescriptor) {
|
|
||||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
|
||||||
if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) {
|
|
||||||
DeclarationDescriptor declarationDescriptor = functionDescriptor.getContainingDeclaration();
|
|
||||||
if (declarationDescriptor != classDescriptor) {
|
|
||||||
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" +
|
|
||||||
// functionDescriptor.getName() + "' declared in " + declarationDescriptor.getName());
|
|
||||||
context.getTrace().report(ABSTRACT_METHOD_NOT_IMPLEMENTED.on(nameIdentifier, klass, functionDescriptor, declarationDescriptor));
|
|
||||||
foundError = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkOverrideForFunction(FunctionDescriptor declaredFunction) {
|
|
||||||
JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction);
|
|
||||||
assert function != null;
|
|
||||||
JetModifierList modifierList = function.getModifierList();
|
|
||||||
ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null;
|
|
||||||
boolean hasOverrideModifier = overrideNode != null;
|
|
||||||
boolean foundError = false;
|
|
||||||
|
|
||||||
for (FunctionDescriptor overridden : declaredFunction.getOverriddenDescriptors()) {
|
|
||||||
if (overridden != null) {
|
|
||||||
if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) {
|
|
||||||
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and cannot be overridden");
|
|
||||||
context.getTrace().report(OVERRIDING_FINAL_FUNCTION.on(overrideNode, overridden, overridden.getContainingDeclaration()));
|
|
||||||
foundError = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) {
|
|
||||||
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing");
|
|
||||||
context.getTrace().report(NOTHING_TO_OVERRIDE.on(function, overrideNode, declaredFunction));
|
|
||||||
}
|
|
||||||
PsiElement nameIdentifier = function.getNameIdentifier();
|
|
||||||
if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) {
|
|
||||||
FunctionDescriptor overriddenFunction = declaredFunction.getOverriddenDescriptors().iterator().next();
|
|
||||||
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(),
|
|
||||||
// "Method '" + declaredFunction.getName() + "' overrides method '" + overriddenFunction.getName() + "' in class " +
|
|
||||||
// overriddenFunction.getContainingDeclaration().getName() + " and needs 'override' modifier");
|
|
||||||
context.getTrace().report(VIRTUAL_METHOD_HIDDEN.on(function, nameIdentifier, declaredFunction, overriddenFunction, overriddenFunction.getContainingDeclaration()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void checkIfPrimaryConstructorIsNecessary() {
|
private void checkIfPrimaryConstructorIsNecessary() {
|
||||||
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
|
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
|
||||||
MutableClassDescriptor classDescriptor = entry.getValue();
|
MutableClassDescriptor classDescriptor = entry.getValue();
|
||||||
|
|||||||
@@ -191,16 +191,10 @@ public class ClassDescriptorResolver {
|
|||||||
returnType = ErrorUtils.createErrorType("No type, no body");
|
returnType = ErrorUtils.createErrorType("No type, no body");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Modality defaultModality;
|
boolean hasBody = function.getBodyExpression() != null;
|
||||||
if (containingDescriptor instanceof ClassDescriptor) {
|
Modality defaultModality = getDefaultModality(containingDescriptor, hasBody);
|
||||||
boolean isDefinitelyAbstract = ((ClassDescriptor) containingDescriptor).getKind() == ClassKind.TRAIT && function.getBodyExpression() == null;
|
|
||||||
defaultModality = isDefinitelyAbstract ? Modality.ABSTRACT : Modality.FINAL;
|
|
||||||
} else {
|
|
||||||
defaultModality = Modality.FINAL;
|
|
||||||
}
|
|
||||||
Modality modality = resolveModalityFromModifiers(trace, function.getModifierList(), defaultModality);
|
Modality modality = resolveModalityFromModifiers(trace, function.getModifierList(), defaultModality);
|
||||||
Visibility visibility = resolveVisibilityFromModifiers(trace, function.getModifierList());
|
Visibility visibility = resolveVisibilityFromModifiers(trace, function.getModifierList());
|
||||||
|
|
||||||
functionDescriptor.initialize(
|
functionDescriptor.initialize(
|
||||||
receiverType,
|
receiverType,
|
||||||
typeParameterDescriptors,
|
typeParameterDescriptors,
|
||||||
@@ -213,6 +207,20 @@ public class ClassDescriptorResolver {
|
|||||||
return functionDescriptor;
|
return functionDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Modality getDefaultModality(DeclarationDescriptor containingDescriptor, boolean isBodyPresent) {
|
||||||
|
Modality defaultModality;
|
||||||
|
if (containingDescriptor instanceof ClassDescriptor) {
|
||||||
|
boolean isTrait = ((ClassDescriptor) containingDescriptor).getKind() == ClassKind.TRAIT;
|
||||||
|
boolean isDefinitelyAbstract = isTrait && !isBodyPresent;
|
||||||
|
Modality basicModality = isTrait ? Modality.OPEN : Modality.FINAL;
|
||||||
|
defaultModality = isDefinitelyAbstract ? Modality.ABSTRACT : basicModality;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
defaultModality = Modality.FINAL;
|
||||||
|
}
|
||||||
|
return defaultModality;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private List<ValueParameterDescriptor> resolveValueParameters(FunctionDescriptor functionDescriptor, WritableScope parameterScope, List<JetParameter> valueParameters) {
|
private List<ValueParameterDescriptor> resolveValueParameters(FunctionDescriptor functionDescriptor, WritableScope parameterScope, List<JetParameter> valueParameters) {
|
||||||
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
|
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
|
||||||
@@ -451,7 +459,6 @@ public class ClassDescriptorResolver {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) {
|
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) {
|
||||||
|
|
||||||
JetScope scopeWithTypeParameters;
|
JetScope scopeWithTypeParameters;
|
||||||
List<TypeParameterDescriptor> typeParameterDescriptors;
|
List<TypeParameterDescriptor> typeParameterDescriptors;
|
||||||
List<JetTypeParameter> typeParameters = property.getTypeParameters();
|
List<JetTypeParameter> typeParameters = property.getTypeParameters();
|
||||||
@@ -477,10 +484,22 @@ public class ClassDescriptorResolver {
|
|||||||
|
|
||||||
JetType type = getVariableType(scopeWithTypeParameters, property, true);
|
JetType type = getVariableType(scopeWithTypeParameters, property, true);
|
||||||
|
|
||||||
|
boolean hasBody = property.getInitializer() != null;
|
||||||
|
if (!hasBody) {
|
||||||
|
JetPropertyAccessor getter = property.getGetter();
|
||||||
|
if (getter != null && getter.getBodyExpression() != null) {
|
||||||
|
hasBody = true;
|
||||||
|
}
|
||||||
|
JetPropertyAccessor setter = property.getSetter();
|
||||||
|
if (!hasBody && setter != null && setter.getBodyExpression() != null) {
|
||||||
|
hasBody = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Modality defaultModality = getDefaultModality(containingDeclaration, hasBody);
|
||||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
|
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
|
||||||
containingDeclaration,
|
containingDeclaration,
|
||||||
annotationResolver.resolveAnnotations(scope, modifierList),
|
annotationResolver.resolveAnnotations(scope, modifierList),
|
||||||
resolveModalityFromModifiers(trace, property.getModifierList()), // TODO : default modifiers differ in different contexts
|
resolveModalityFromModifiers(trace, property.getModifierList(), defaultModality),
|
||||||
resolveVisibilityFromModifiers(trace, property.getModifierList()),
|
resolveVisibilityFromModifiers(trace, property.getModifierList()),
|
||||||
isVar,
|
isVar,
|
||||||
receiverType,
|
receiverType,
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.intellij.lang.ASTNode;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class OverrideResolver {
|
||||||
|
|
||||||
|
private final TopDownAnalysisContext context;
|
||||||
|
|
||||||
|
public OverrideResolver(@NotNull TopDownAnalysisContext context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void process() {
|
||||||
|
bindOverrides();
|
||||||
|
checkOverrides();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bindOverrides() {
|
||||||
|
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
|
||||||
|
bindOverridesInAClass(entry.getValue());
|
||||||
|
}
|
||||||
|
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
|
||||||
|
bindOverridesInAClass(entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) {
|
||||||
|
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
|
||||||
|
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
|
||||||
|
FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype);
|
||||||
|
if (overridden != null) {
|
||||||
|
((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
|
||||||
|
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
|
||||||
|
PropertyDescriptor overridden = findPropertyOverridableBy(propertyDescriptor, supertype);
|
||||||
|
if (overridden != null) {
|
||||||
|
propertyDescriptor.addOverriddenDescriptor(overridden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) {
|
||||||
|
FunctionGroup functionGroup = supertype.getMemberScope().getFunctionGroup(declaredFunction.getName());
|
||||||
|
for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) {
|
||||||
|
if (OverridingUtil.isOverridableBy(context.getSemanticServices().getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) {
|
||||||
|
return functionDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private PropertyDescriptor findPropertyOverridableBy(@NotNull PropertyDescriptor declaredProperty, @NotNull JetType supertype) {
|
||||||
|
PropertyDescriptor property = (PropertyDescriptor) supertype.getMemberScope().getVariable(declaredProperty.getName());
|
||||||
|
if (property == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (OverridingUtil.isOverridableBy(context.getSemanticServices().getTypeChecker(), property, declaredProperty).isSuccess()) {
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkOverrides() {
|
||||||
|
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
|
||||||
|
checkOverridesInAClass(entry.getValue(), entry.getKey());
|
||||||
|
}
|
||||||
|
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
|
||||||
|
checkOverridesInAClass(entry.getValue(), entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
|
||||||
|
|
||||||
|
Set<FunctionDescriptor> inheritedFunctions = Sets.newLinkedHashSet();
|
||||||
|
Set<PropertyDescriptor> inheritedProperties = Sets.newLinkedHashSet();
|
||||||
|
for (JetType supertype : classDescriptor.getSupertypes()) {
|
||||||
|
for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) {
|
||||||
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
|
inheritedFunctions.add(functionDescriptor);
|
||||||
|
}
|
||||||
|
else if (descriptor instanceof PropertyDescriptor) {
|
||||||
|
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||||
|
inheritedProperties.add(propertyDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OverridingUtil.filterOverrides(inheritedFunctions);
|
||||||
|
OverridingUtil.filterOverrides(inheritedProperties);
|
||||||
|
|
||||||
|
// System.out.println(classDescriptor);
|
||||||
|
// println(inheritedFunctions);
|
||||||
|
// println(inheritedProperties);
|
||||||
|
|
||||||
|
|
||||||
|
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
|
||||||
|
checkOverrideForFunction(declaredFunction);
|
||||||
|
}
|
||||||
|
if (classDescriptor.getModality() == Modality.ABSTRACT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<FunctionDescriptor> allOverriddenFunctions = Sets.newHashSet();
|
||||||
|
Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors();
|
||||||
|
for (DeclarationDescriptor descriptor : allDescriptors) {
|
||||||
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
|
if (functionDescriptor.getModality() != Modality.ABSTRACT) {
|
||||||
|
for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
|
||||||
|
allOverriddenFunctions.add(overriddenDescriptor.getOriginal());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean foundError = false;
|
||||||
|
PsiElement nameIdentifier = null;
|
||||||
|
if (klass instanceof JetClass) {
|
||||||
|
nameIdentifier = ((JetClass) klass).getNameIdentifier();
|
||||||
|
}
|
||||||
|
else if (klass instanceof JetObjectDeclaration) {
|
||||||
|
nameIdentifier = ((JetObjectDeclaration) klass).getNameIdentifier();
|
||||||
|
}
|
||||||
|
for (DeclarationDescriptor descriptor : allDescriptors) {
|
||||||
|
if (descriptor instanceof FunctionDescriptor) {
|
||||||
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
|
if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) {
|
||||||
|
DeclarationDescriptor declarationDescriptor = functionDescriptor.getContainingDeclaration();
|
||||||
|
if (declarationDescriptor != classDescriptor) {
|
||||||
|
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" +
|
||||||
|
// functionDescriptor.getName() + "' declared in " + declarationDescriptor.getName());
|
||||||
|
context.getTrace().report(ABSTRACT_METHOD_NOT_IMPLEMENTED.on(nameIdentifier, klass, functionDescriptor, declarationDescriptor));
|
||||||
|
foundError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void println(Set<? extends CallableDescriptor> inheritedProperties) {
|
||||||
|
for (CallableDescriptor inheritedProperty : inheritedProperties) {
|
||||||
|
System.out.println(" " + inheritedProperty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void checkOverrideForFunction(FunctionDescriptor declaredFunction) {
|
||||||
|
JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction);
|
||||||
|
assert function != null;
|
||||||
|
JetModifierList modifierList = function.getModifierList();
|
||||||
|
ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null;
|
||||||
|
boolean hasOverrideModifier = overrideNode != null;
|
||||||
|
boolean foundError = false;
|
||||||
|
|
||||||
|
for (FunctionDescriptor overridden : declaredFunction.getOverriddenDescriptors()) {
|
||||||
|
if (overridden != null) {
|
||||||
|
if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) {
|
||||||
|
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and cannot be overridden");
|
||||||
|
context.getTrace().report(OVERRIDING_FINAL_FUNCTION.on(overrideNode, overridden, overridden.getContainingDeclaration()));
|
||||||
|
foundError = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) {
|
||||||
|
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing");
|
||||||
|
context.getTrace().report(NOTHING_TO_OVERRIDE.on(function, overrideNode, declaredFunction));
|
||||||
|
}
|
||||||
|
PsiElement nameIdentifier = function.getNameIdentifier();
|
||||||
|
if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) {
|
||||||
|
FunctionDescriptor overriddenFunction = declaredFunction.getOverriddenDescriptors().iterator().next();
|
||||||
|
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(),
|
||||||
|
// "Method '" + declaredFunction.getName() + "' overrides method '" + overriddenFunction.getName() + "' in class " +
|
||||||
|
// overriddenFunction.getContainingDeclaration().getName() + " and needs 'override' modifier");
|
||||||
|
context.getTrace().report(VIRTUAL_METHOD_HIDDEN.on(function, nameIdentifier, declaredFunction, overriddenFunction, overriddenFunction.getContainingDeclaration()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
|
import com.google.common.collect.BiMap;
|
||||||
|
import com.google.common.collect.HashBiMap;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
|
import org.jetbrains.jet.lang.types.*;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author abreslav
|
||||||
|
*/
|
||||||
|
public class OverridingUtil {
|
||||||
|
|
||||||
|
public static Set<CallableDescriptor> getEffectiveMembers(@NotNull ClassDescriptor classDescriptor) {
|
||||||
|
Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors();
|
||||||
|
Set<CallableDescriptor> allMembers = Sets.newLinkedHashSet();
|
||||||
|
for (DeclarationDescriptor descriptor : allDescriptors) {
|
||||||
|
assert !(descriptor instanceof ConstructorDescriptor);
|
||||||
|
if (descriptor instanceof CallableDescriptor && descriptor instanceof MemberDescriptor) {
|
||||||
|
CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor;
|
||||||
|
if (((MemberDescriptor) descriptor).getModality() != Modality.ABSTRACT) {
|
||||||
|
allMembers.add(callableDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filterOverrides(allMembers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <D extends CallableDescriptor> Set<D> filterOverrides(Set<D> candidateSet) {
|
||||||
|
Set<D> candidates = Sets.newLinkedHashSet();
|
||||||
|
outerLoop:
|
||||||
|
for (D me : candidateSet) {
|
||||||
|
for (D other : candidateSet) {
|
||||||
|
if (me == other) continue;
|
||||||
|
if (overrides(other, me)) {
|
||||||
|
continue outerLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (D other : candidates) {
|
||||||
|
if (me.getOriginal() == other.getOriginal()
|
||||||
|
&& isOverridableBy(JetTypeChecker.INSTANCE, other, me).isSuccess()
|
||||||
|
&& isOverridableBy(JetTypeChecker.INSTANCE, me, other).isSuccess()) {
|
||||||
|
continue outerLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// System.out.println(me);
|
||||||
|
candidates.add(me);
|
||||||
|
}
|
||||||
|
// Set<D> candidates = Sets.newLinkedHashSet(candidateSet);
|
||||||
|
// for (D descriptor : candidateSet) {
|
||||||
|
// Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
|
||||||
|
// getAllOverriddenDescriptors(descriptor.getOriginal(), overriddenDescriptors);
|
||||||
|
// candidates.removeAll(overriddenDescriptors);
|
||||||
|
// }
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <Descriptor extends CallableDescriptor> boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) {
|
||||||
|
Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
|
||||||
|
getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors);
|
||||||
|
CallableDescriptor originalG = g.getOriginal();
|
||||||
|
for (CallableDescriptor overriddenFunction : overriddenDescriptors) {
|
||||||
|
if (originalG.equals(overriddenFunction.getOriginal())) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set<CallableDescriptor> overriddenDescriptors) {
|
||||||
|
if (overriddenDescriptors.contains(current)) return;
|
||||||
|
for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) {
|
||||||
|
getAllOverriddenDescriptors(descriptor, overriddenDescriptors);
|
||||||
|
overriddenDescriptors.add(descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo isOverridableBy(@NotNull JetTypeChecker typeChecker, @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
||||||
|
if (!superDescriptor.getName().equals(subDescriptor.getName())) {
|
||||||
|
return OverrideCompatibilityInfo.nameMismatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : Visibility
|
||||||
|
|
||||||
|
if (superDescriptor.getTypeParameters().size() != subDescriptor.getTypeParameters().size()) {
|
||||||
|
return OverrideCompatibilityInfo.typeParameterNumberMismatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
|
||||||
|
return OverrideCompatibilityInfo.valueParameterNumberMismatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
|
||||||
|
List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
|
||||||
|
|
||||||
|
Map<TypeConstructor, TypeProjection> substitutionContext = Maps.newHashMap();
|
||||||
|
BiMap<TypeConstructor, TypeConstructor> axioms = HashBiMap.create();
|
||||||
|
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
||||||
|
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
||||||
|
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
||||||
|
substitutionContext.put(
|
||||||
|
superTypeParameter.getTypeConstructor(),
|
||||||
|
new TypeProjection(subTypeParameter.getDefaultType()));
|
||||||
|
axioms.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
||||||
|
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
||||||
|
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
||||||
|
|
||||||
|
|
||||||
|
if (!JetTypeImpl.equalTypes(superTypeParameter.getBoundsAsType(), subTypeParameter.getBoundsAsType(), axioms)) {
|
||||||
|
return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ValueParameterDescriptor> superValueParameters = superDescriptor.getValueParameters();
|
||||||
|
List<ValueParameterDescriptor> subValueParameters = subDescriptor.getValueParameters();
|
||||||
|
for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
|
||||||
|
ValueParameterDescriptor superValueParameter = superValueParameters.get(i);
|
||||||
|
ValueParameterDescriptor subValueParameter = subValueParameters.get(i);
|
||||||
|
|
||||||
|
if (!JetTypeImpl.equalTypes(superValueParameter.getOutType(), subValueParameter.getOutType(), axioms)) {
|
||||||
|
return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO : Default values, varargs etc
|
||||||
|
|
||||||
|
TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitutionContext);
|
||||||
|
JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getReturnType(), Variance.OUT_VARIANCE);
|
||||||
|
assert substitutedSuperReturnType != null;
|
||||||
|
if (!typeChecker.isSubtypeOf(subDescriptor.getReturnType(), substitutedSuperReturnType)) {
|
||||||
|
return OverrideCompatibilityInfo.returnTypeMismatch(substitutedSuperReturnType, subDescriptor.getReturnType());
|
||||||
|
}
|
||||||
|
|
||||||
|
return OverrideCompatibilityInfo.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OverrideCompatibilityInfo {
|
||||||
|
|
||||||
|
private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(true, "SUCCESS");
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo success() {
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo nameMismatch() {
|
||||||
|
return new OverrideCompatibilityInfo(false, "nameMismatch"); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo typeParameterNumberMismatch() {
|
||||||
|
return new OverrideCompatibilityInfo(false, "typeParameterNumberMismatch"); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo valueParameterNumberMismatch() {
|
||||||
|
return new OverrideCompatibilityInfo(false, "valueParameterNumberMismatch"); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo boundsMismatch(TypeParameterDescriptor superTypeParameter, TypeParameterDescriptor subTypeParameter) {
|
||||||
|
return new OverrideCompatibilityInfo(false, "boundsMismatch"); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo valueParameterTypeMismatch(ValueParameterDescriptor superValueParameter, ValueParameterDescriptor subValueParameter) {
|
||||||
|
return new OverrideCompatibilityInfo(false, "valueParameterTypeMismatch"); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo returnTypeMismatch(JetType substitutedSuperReturnType, JetType unsubstitutedSubReturnType) {
|
||||||
|
return new OverrideCompatibilityInfo(false, "returnTypeMismatch: " + unsubstitutedSubReturnType + " >< " + substitutedSuperReturnType); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static OverrideCompatibilityInfo varOverriddenByVal() {
|
||||||
|
return new OverrideCompatibilityInfo(false, "varOverriddenByVal"); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private final boolean isSuccess;
|
||||||
|
private final String message;
|
||||||
|
|
||||||
|
public OverrideCompatibilityInfo(boolean success, String message) {
|
||||||
|
isSuccess = success;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return isSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,6 +65,7 @@ public class TopDownAnalyzer {
|
|||||||
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
|
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
|
||||||
new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
|
new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
|
||||||
new DeclarationResolver(context).process();
|
new DeclarationResolver(context).process();
|
||||||
|
new OverrideResolver(context).process();
|
||||||
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +78,12 @@ public class TopDownAnalyzer {
|
|||||||
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
|
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
|
||||||
new TypeHierarchyResolver(context).process(outerScope, standardLibraryNamespace, namespace.getDeclarations());
|
new TypeHierarchyResolver(context).process(outerScope, standardLibraryNamespace, namespace.getDeclarations());
|
||||||
new DeclarationResolver(context).process();
|
new DeclarationResolver(context).process();
|
||||||
|
OverrideResolver overrideResolver = new OverrideResolver(context) {
|
||||||
|
@Override
|
||||||
|
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
overrideResolver.process();
|
||||||
BodyResolver bodyResolver = new BodyResolver(context) {
|
BodyResolver bodyResolver = new BodyResolver(context) {
|
||||||
@Override
|
@Override
|
||||||
protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) {
|
protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) {
|
||||||
@@ -85,10 +92,6 @@ public class TopDownAnalyzer {
|
|||||||
@Override
|
@Override
|
||||||
protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
|
protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
bodyResolver.resolveBehaviorDeclarationBodies();
|
bodyResolver.resolveBehaviorDeclarationBodies();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ public class CallResolver {
|
|||||||
return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated);
|
return OverloadResolutionResult.success(maximallySpecificGenericsDiscriminated);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<D> noOverrides = filterOverrides(successfulCandidates.keySet());
|
Set<D> noOverrides = OverridingUtil.filterOverrides(successfulCandidates.keySet());
|
||||||
if (dirtyCandidates.isEmpty()) {
|
if (dirtyCandidates.isEmpty()) {
|
||||||
// tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: "
|
// tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: "
|
||||||
// + makeErrorMessageForMultipleDescriptors(noOverrides));
|
// + makeErrorMessageForMultipleDescriptors(noOverrides));
|
||||||
@@ -547,7 +547,7 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
else if (!failedCandidates.isEmpty()) {
|
else if (!failedCandidates.isEmpty()) {
|
||||||
if (failedCandidates.size() != 1) {
|
if (failedCandidates.size() != 1) {
|
||||||
Set<D> noOverrides = filterOverrides(failedCandidates);
|
Set<D> noOverrides = OverridingUtil.filterOverrides(failedCandidates);
|
||||||
if (noOverrides.size() != 1) {
|
if (noOverrides.size() != 1) {
|
||||||
// tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: "
|
// tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: "
|
||||||
// + makeErrorMessageForMultipleDescriptors(noOverrides));
|
// + makeErrorMessageForMultipleDescriptors(noOverrides));
|
||||||
@@ -568,20 +568,6 @@ public class CallResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <D extends CallableDescriptor> Set<D> filterOverrides(Set<D> candidateSet) {
|
|
||||||
Set<D> candidates = Sets.newLinkedHashSet();
|
|
||||||
outerLoop:
|
|
||||||
for (D me : candidateSet) {
|
|
||||||
for (D other : candidateSet) {
|
|
||||||
if (OverloadingConflictResolver.overrides(other, me)) {
|
|
||||||
continue outerLoop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
candidates.add(me);
|
|
||||||
}
|
|
||||||
return candidates;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters, Flag dirty, Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
|
private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters, Flag dirty, Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
|
||||||
|
|||||||
+4
-23
@@ -1,13 +1,13 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.calls;
|
package org.jetbrains.jet.lang.resolve.calls;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
|
import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
||||||
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||||
@@ -15,12 +15,11 @@ import org.jetbrains.jet.lang.types.JetType;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
/*package*/ class OverloadingConflictResolver {
|
public class OverloadingConflictResolver {
|
||||||
|
|
||||||
private final JetSemanticServices semanticServices;
|
private final JetSemanticServices semanticServices;
|
||||||
|
|
||||||
@@ -57,8 +56,8 @@ import java.util.Set;
|
|||||||
* Int < Short < Byte
|
* Int < Short < Byte
|
||||||
*/
|
*/
|
||||||
private <Descriptor extends CallableDescriptor> boolean moreSpecific(Descriptor f, Descriptor g, boolean discriminateGenericDescriptors) {
|
private <Descriptor extends CallableDescriptor> boolean moreSpecific(Descriptor f, Descriptor g, boolean discriminateGenericDescriptors) {
|
||||||
if (overrides(f, g)) return true;
|
if (OverridingUtil.overrides(f, g)) return true;
|
||||||
if (overrides(g, f)) return false;
|
if (OverridingUtil.overrides(g, f)) return false;
|
||||||
|
|
||||||
ReceiverDescriptor receiverOfF = f.getReceiver();
|
ReceiverDescriptor receiverOfF = f.getReceiver();
|
||||||
ReceiverDescriptor receiverOfG = g.getReceiver();
|
ReceiverDescriptor receiverOfG = g.getReceiver();
|
||||||
@@ -121,22 +120,4 @@ import java.util.Set;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <Descriptor extends CallableDescriptor> boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) {
|
|
||||||
Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
|
|
||||||
getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors);
|
|
||||||
CallableDescriptor originalG = g.getOriginal();
|
|
||||||
for (CallableDescriptor overriddenFunction : overriddenDescriptors) {
|
|
||||||
if (originalG.equals(overriddenFunction.getOriginal())) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set<CallableDescriptor> overriddenDescriptors) {
|
|
||||||
if (overriddenDescriptors.contains(current)) return;
|
|
||||||
for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) {
|
|
||||||
getAllOverriddenDescriptors(descriptor, overriddenDescriptors);
|
|
||||||
overriddenDescriptors.add(descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ public class DescriptorRenderer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) {
|
public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) {
|
||||||
|
renderModality(descriptor.getModality(), builder);
|
||||||
String typeString = renderPropertyPrefixAndComputeTypeString(
|
String typeString = renderPropertyPrefixAndComputeTypeString(
|
||||||
builder, descriptor.getTypeParameters(),
|
builder, descriptor.getTypeParameters(),
|
||||||
descriptor.getReceiver(),
|
descriptor.getReceiver(),
|
||||||
@@ -182,8 +183,24 @@ public class DescriptorRenderer {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderModality(Modality modality, StringBuilder builder) {
|
||||||
|
switch (modality) {
|
||||||
|
case FINAL:
|
||||||
|
builder.append("final");
|
||||||
|
break;
|
||||||
|
case OPEN:
|
||||||
|
builder.append("open");
|
||||||
|
break;
|
||||||
|
case ABSTRACT:
|
||||||
|
builder.append("abstract");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
builder.append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) {
|
public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) {
|
||||||
|
renderModality(descriptor.getModality(), builder);
|
||||||
builder.append(renderKeyword("fun")).append(" ");
|
builder.append(renderKeyword("fun")).append(" ");
|
||||||
renderTypeParameters(descriptor.getTypeParameters(), builder);
|
renderTypeParameters(descriptor.getTypeParameters(), builder);
|
||||||
|
|
||||||
@@ -259,6 +276,7 @@ public class DescriptorRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void renderClassDescriptor(ClassDescriptor descriptor, StringBuilder builder, String keyword) {
|
public void renderClassDescriptor(ClassDescriptor descriptor, StringBuilder builder, String keyword) {
|
||||||
|
renderModality(descriptor.getModality(), builder);
|
||||||
builder.append(renderKeyword(keyword)).append(" ");
|
builder.append(renderKeyword(keyword)).append(" ");
|
||||||
renderName(descriptor, builder);
|
renderName(descriptor, builder);
|
||||||
renderTypeParameters(descriptor.getTypeConstructor().getParameters(), builder);
|
renderTypeParameters(descriptor.getTypeConstructor().getParameters(), builder);
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,10 @@
|
|||||||
|
// KT-316 Members of traits must be open by default
|
||||||
|
|
||||||
|
trait B {
|
||||||
|
fun bar() {}
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class A() : B{
|
||||||
|
override fun foo() {}
|
||||||
|
}
|
||||||
@@ -81,7 +81,7 @@ public abstract class JetLiteFixture extends PlatformLiteFixture {
|
|||||||
public void verify(PicoContainer container) throws PicoIntrospectionException {
|
public void verify(PicoContainer container) throws PicoIntrospectionException {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
myProject = disposeOnTearDown(new MockProjectEx());
|
myProject = disposeOnTearDown(new MockProjectEx(getTestRootDisposable()));
|
||||||
myPsiManager = new MockPsiManager(myProject);
|
myPsiManager = new MockPsiManager(myProject);
|
||||||
myFileFactory = new PsiFileFactoryImpl(myPsiManager);
|
myFileFactory = new PsiFileFactoryImpl(myPsiManager);
|
||||||
final MutablePicoContainer appContainer = getApplication().getPicoContainer();
|
final MutablePicoContainer appContainer = getApplication().getPicoContainer();
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import com.intellij.openapi.application.PathManager;
|
|||||||
import org.jetbrains.jet.JetTestUtils;
|
import org.jetbrains.jet.JetTestUtils;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptorUtil;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetPsiFactory;
|
import org.jetbrains.jet.lang.psi.JetPsiFactory;
|
||||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||||
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
|
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.OverridingUtil;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.parsing.JetParsingTest;
|
import org.jetbrains.jet.parsing.JetParsingTest;
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ public class JetOverridingTest extends LightDaemonAnalyzerTestCase {
|
|||||||
private void assertOverridabilityRelation(String superFun, String subFun, boolean expectedIsError) {
|
private void assertOverridabilityRelation(String superFun, String subFun, boolean expectedIsError) {
|
||||||
FunctionDescriptor a = makeFunction(superFun);
|
FunctionDescriptor a = makeFunction(superFun);
|
||||||
FunctionDescriptor b = makeFunction(subFun);
|
FunctionDescriptor b = makeFunction(subFun);
|
||||||
FunctionDescriptorUtil.OverrideCompatibilityInfo overridableWith = FunctionDescriptorUtil.isOverridableBy(semanticServices.getTypeChecker(), a, b);
|
OverridingUtil.OverrideCompatibilityInfo overridableWith = OverridingUtil.isOverridableBy(semanticServices.getTypeChecker(), a, b);
|
||||||
assertEquals(overridableWith.getMessage(), expectedIsError, !overridableWith.isSuccess());
|
assertEquals(overridableWith.getMessage(), expectedIsError, !overridableWith.isSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user