Basic overload resolution supported

This commit is contained in:
Andrey Breslav
2011-03-11 17:41:18 +03:00
parent 28a88faf61
commit 917dfd402e
17 changed files with 325 additions and 120 deletions
@@ -1,7 +1,9 @@
package org.jetbrains.jet.lang;
import com.intellij.lang.ASTNode;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.types.Type;
/**
* @author abreslav
@@ -18,6 +20,11 @@ public class ErrorHandler {
public void structuralError(ASTNode node, String errorMessage) {
throw new IllegalStateException(errorMessage);
}
@Override
public void typeMismatch(JetExpression expression, Type expectedType, Type actualType) {
throw new IllegalStateException("Type mismatch: inferred type is " + actualType + " but " + expectedType + " was expected");
}
};
public void unresolvedReference(JetReferenceExpression referenceExpression) {
@@ -25,4 +32,7 @@ public class ErrorHandler {
public void structuralError(ASTNode node, String errorMessage) {
}
public void typeMismatch(JetExpression expression, Type expectedType, Type actualType) {
}
}
@@ -1,9 +1,12 @@
package org.jetbrains.jet.lang;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
import org.jetbrains.jet.lang.resolve.OverloadResolver;
import org.jetbrains.jet.lang.types.BindingTrace;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lang.types.JetTypeInferrer;
/**
@@ -20,6 +23,8 @@ public class JetSemanticServices {
private final JetTypeInferrer typeInferrer;
private final JetStandardLibrary standardLibrary;
private final JetTypeChecker typeChecker;
private final OverloadResolver overloadResolver;
private final ErrorHandler errorHandler;
@@ -27,25 +32,42 @@ public class JetSemanticServices {
this.standardLibrary = standardLibrary;
this.errorHandler = errorHandler;
this.typeInferrer = new JetTypeInferrer(BindingTrace.DUMMY, this);
this.typeChecker = new JetTypeChecker(standardLibrary);
this.overloadResolver = new OverloadResolver(typeChecker);
}
@NotNull
public JetStandardLibrary getStandardLibrary() {
return standardLibrary;
}
@NotNull
public JetTypeInferrer getTypeInferrer() {
return typeInferrer;
}
@NotNull
public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) {
return new ClassDescriptorResolver(this, trace);
}
@NotNull
public JetTypeInferrer getTypeInferrer(BindingTrace trace) {
return new JetTypeInferrer(trace, this);
}
@NotNull
public ErrorHandler getErrorHandler() {
return errorHandler;
}
@NotNull
public JetTypeChecker getTypeChecker() {
return typeChecker;
}
@NotNull
public OverloadResolver getOverloadResolver() {
return overloadResolver;
}
}
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.annotations;
import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.project.Project;
@@ -29,6 +30,16 @@ public class JetPsiChecker implements Annotator {
public void unresolvedReference(JetReferenceExpression referenceExpression) {
holder.createErrorAnnotation(referenceExpression, "Unresolved");
}
@Override
public void structuralError(ASTNode node, String errorMessage) {
holder.createErrorAnnotation(node, errorMessage);
}
@Override
public void typeMismatch(JetExpression expression, Type expectedType, Type actualType) {
holder.createErrorAnnotation(expression, "Type mismatch: inferred type is " + actualType + " but " + expectedType + " was expected");
}
});
file.getRootNamespace().accept(new JetVisitor() {
@Override
@@ -4,19 +4,18 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* @author abreslav
*/
public class OverloadResolver {
public static final OverloadResolver INSTANCE = new OverloadResolver();
private final JetTypeChecker typeChecker;
private OverloadResolver() {}
public OverloadResolver(JetTypeChecker typeChecker) {
this.typeChecker = typeChecker;
}
@NotNull
public OverloadDomain getOverloadDomain(Type receiverType, @NotNull JetScope outerScope, @NotNull String name) {
@@ -54,7 +53,7 @@ public class OverloadResolver {
Type argumentType = positionedValueArgumentTypes.get(i);
Type parameterType = parameters.get(i).getType();
// TODO : handle vararg cases here
if (!JetTypeChecker.INSTANCE.isConvertibleTo(argumentType, parameterType)) {
if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
continue descLoop;
}
}
@@ -64,14 +63,14 @@ public class OverloadResolver {
for (int i = 0; i < nonVarargs; i++) {
Type argumentType = positionedValueArgumentTypes.get(i);
Type parameterType = parameters.get(i).getType();
if (!JetTypeChecker.INSTANCE.isConvertibleTo(argumentType, parameterType)) {
if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
continue descLoop;
}
}
Type varArgType = parameters.get(nonVarargs).getType();
for (int i = nonVarargs, args = positionedValueArgumentTypes.size(); i < args; i++) {
Type argumentType = positionedValueArgumentTypes.get(i);
if (!JetTypeChecker.INSTANCE.isConvertibleTo(argumentType, varArgType)) {
if (!typeChecker.isConvertibleTo(argumentType, varArgType)) {
continue descLoop;
}
}
@@ -84,6 +83,23 @@ public class OverloadResolver {
} else if (applicable.size() == 1) {
return applicable.get(0);
} else {
// TODO : varargs
List<FunctionDescriptor> maximallySpecific = new ArrayList<FunctionDescriptor>();
meLoop:
for (FunctionDescriptor me : applicable) {
for (FunctionDescriptor other : applicable) {
if (other == me) continue;
if (!moreSpecific(me, other) || moreSpecific(other, me)) continue meLoop;
}
maximallySpecific.add(me);
}
if (maximallySpecific.isEmpty()) {
return null;
}
if (maximallySpecific.size() == 1) {
return maximallySpecific.get(0);
}
throw new UnsupportedOperationException();
}
}
@@ -95,4 +111,22 @@ public class OverloadResolver {
};
}
private boolean moreSpecific(FunctionDescriptor f, FunctionDescriptor g) {
List<ValueParameterDescriptor> fParams = f.getUnsubstitutedValueParameters();
List<ValueParameterDescriptor> gParams = g.getUnsubstitutedValueParameters();
int fSize = fParams.size();
if (fSize != gParams.size()) return false;
for (int i = 0; i < fSize; i++) {
Type fParamType = fParams.get(i).getType();
Type gParamType = gParams.get(i).getType();
// TODO : maybe isSubtypeOf is sufficient?
if (!typeChecker.isConvertibleTo(fParamType, gParamType)) {
return false;
}
}
return true;
}
}
@@ -36,76 +36,78 @@ public class TypeResolver {
private Type resolveTypeElement(final JetScope scope, final List<Attribute> attributes, JetTypeElement typeElement, final boolean nullable) {
final Type[] result = new Type[1];
typeElement.accept(new JetVisitor() {
@Override
public void visitUserType(JetUserType type) {
ClassDescriptor classDescriptor = resolveClass(scope, type);
if (classDescriptor != null) {
trace.recordReferenceResolution(type.getReferenceExpression(), classDescriptor);
TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments());
result[0] = new TypeImpl(
attributes,
typeConstructor,
nullable,
arguments,
classDescriptor.getMemberScope(arguments)
);
}
else if (type.getTypeArguments().isEmpty()) {
TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(type.getReferencedName());
if (typeParameterDescriptor != null) {
trace.recordReferenceResolution(type.getReferenceExpression(), typeParameterDescriptor);
if (typeElement != null) {
typeElement.accept(new JetVisitor() {
@Override
public void visitUserType(JetUserType type) {
ClassDescriptor classDescriptor = resolveClass(scope, type);
if (classDescriptor != null) {
trace.recordReferenceResolution(type.getReferenceExpression(), classDescriptor);
TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments());
result[0] = new TypeImpl(
attributes,
typeParameterDescriptor.getTypeConstructor(),
nullable || hasNullableBound(typeParameterDescriptor),
Collections.<TypeProjection>emptyList(),
// TODO : joint domain
JetStandardClasses.STUB
typeConstructor,
nullable,
arguments,
classDescriptor.getMemberScope(arguments)
);
} else {
}
else if (type.getTypeArguments().isEmpty()) {
TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(type.getReferencedName());
if (typeParameterDescriptor != null) {
trace.recordReferenceResolution(type.getReferenceExpression(), typeParameterDescriptor);
result[0] = new TypeImpl(
attributes,
typeParameterDescriptor.getTypeConstructor(),
nullable || hasNullableBound(typeParameterDescriptor),
Collections.<TypeProjection>emptyList(),
// TODO : joint domain
JetStandardClasses.STUB
);
} else {
semanticServices.getErrorHandler().unresolvedReference(type.getReferenceExpression());
}
}
else {
semanticServices.getErrorHandler().unresolvedReference(type.getReferenceExpression());
}
}
else {
semanticServices.getErrorHandler().unresolvedReference(type.getReferenceExpression());
}
}
@Override
public void visitNullableType(JetNullableType nullableType) {
result[0] = resolveTypeElement(scope, attributes, nullableType.getInnerType(), true);
}
@Override
public void visitTupleType(JetTupleType type) {
// TODO labels
result[0] = JetStandardClasses.getTupleType(resolveTypes(scope, type.getComponentTypeRefs()));
}
@Override
public void visitFunctionType(JetFunctionType type) {
JetTypeReference receiverTypeRef = type.getReceiverTypeRef();
Type receiverType = receiverTypeRef == null ? null : resolveType(scope, receiverTypeRef);
List<Type> parameterTypes = new ArrayList<Type>();
for (JetParameter parameter : type.getParameters()) {
parameterTypes.add(resolveType(scope, parameter.getTypeReference()));
@Override
public void visitNullableType(JetNullableType nullableType) {
result[0] = resolveTypeElement(scope, attributes, nullableType.getInnerType(), true);
}
Type returnType = resolveType(scope, type.getReturnTypeRef());
@Override
public void visitTupleType(JetTupleType type) {
// TODO labels
result[0] = JetStandardClasses.getTupleType(resolveTypes(scope, type.getComponentTypeRefs()));
}
result[0] = JetStandardClasses.getFunctionType(attributes, receiverType, parameterTypes, returnType);
}
@Override
public void visitFunctionType(JetFunctionType type) {
JetTypeReference receiverTypeRef = type.getReceiverTypeRef();
Type receiverType = receiverTypeRef == null ? null : resolveType(scope, receiverTypeRef);
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported type: " + elem);
}
});
List<Type> parameterTypes = new ArrayList<Type>();
for (JetParameter parameter : type.getParameters()) {
parameterTypes.add(resolveType(scope, parameter.getTypeReference()));
}
Type returnType = resolveType(scope, type.getReturnTypeRef());
result[0] = JetStandardClasses.getFunctionType(attributes, receiverType, parameterTypes, returnType);
}
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported type: " + elem);
}
});
}
if (result[0] == null) {
return ErrorType.createErrorType(typeElement.getText());
return ErrorType.createErrorType(typeElement == null ? "No type element": typeElement.getText());
}
return result[0];
}
@@ -137,7 +139,7 @@ public class TypeResolver {
Type type;
if (projectionKind == JetProjectionKind.STAR) {
Set<Type> upperBounds = constructor.getParameters().get(i).getUpperBounds();
arguments.add(new TypeProjection(Variance.OUT_VARIANCE, TypeUtils.intersect(upperBounds)));
arguments.add(new TypeProjection(Variance.OUT_VARIANCE, TypeUtils.intersect(semanticServices.getTypeChecker(), upperBounds)));
}
else {
// TODO : handle the Foo<in *> case
@@ -61,6 +61,6 @@ public class WritableFunctionGroup implements FunctionGroup {
@Override
public boolean isEmpty() {
return functionDescriptors.isEmpty();
return functionDescriptors == null || functionDescriptors.isEmpty();
}
}
@@ -160,6 +160,7 @@ public class WritableScope extends JetScopeAdapter {
public void addClassAlias(String name, ClassDescriptor classDescriptor) {
Map<String, ClassDescriptor> classDescriptors = getClassDescriptors();
if (classDescriptors.put(name, classDescriptor) != null) {
throw new UnsupportedOperationException("Class redeclared: " + classDescriptor.getName());
}
}
@@ -72,22 +72,22 @@ public class JavaClassMembersScope implements JetScope {
@Override
public ExtensionDescriptor getExtension(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO
return null;
}
@Override
public NamespaceDescriptor getNamespace(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO
return null;
}
@Override
public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO
return null;
}
@NotNull
@Override
public Type getThisType() {
throw new UnsupportedOperationException(); // TODO
return null;
}
}
@@ -59,13 +59,29 @@ public class JavaDescriptorResolver {
modifierList == null ? false : modifierList.hasModifierProperty(PsiModifier.FINAL),
name,
Collections.<TypeParameterDescriptor>emptyList(),
Collections.<Type>emptyList(),
getSupertypes(psiClass),
new JavaClassMembersScope(psiClass, semanticServices, false)
);
semanticServices.getTrace().recordDeclarationResolution(psiClass, classDescriptor);
return classDescriptor;
}
private Collection<? extends Type> getSupertypes(PsiClass psiClass) {
List<Type> result = new ArrayList<Type>();
result.add(JetStandardClasses.getAnyType());
transformSupertypeList(result, psiClass.getExtendsListTypes());
transformSupertypeList(result, psiClass.getImplementsListTypes());
return result;
}
private void transformSupertypeList(List<Type> result, PsiClassType[] extendsListTypes) {
for (PsiClassType type : extendsListTypes) {
Type transform = semanticServices.getTypeTransformer().transform(type);
result.add(TypeUtils.makeNotNullable(transform));
}
}
public NamespaceDescriptor resolveNamespace(String qualifiedName) {
NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(qualifiedName);
if (namespaceDescriptor == null) {
@@ -4,7 +4,9 @@ import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@@ -23,13 +25,25 @@ public class JavaTypeTransformer {
@NotNull
public Type transform(PsiType javaType) {
Type result = javaType.accept(new PsiTypeVisitor<Type>() {
return javaType.accept(new PsiTypeVisitor<Type>() {
@Override
public Type visitClassType(PsiClassType classType) {
PsiClass psiClass = classType.resolveGenerics().getElement();
if (psiClass == null) {
return ErrorType.createErrorType("Unresolved java class: " + classType.getPresentableText());
}
if ("java.lang.Object".equals(psiClass.getQualifiedName())) {
return JetStandardClasses.getNullableAnyType();
}
ClassDescriptor descriptor = resolver.resolveClass(psiClass);
// TODO : parameters
return new TypeImpl(descriptor);
// TODO : arguments & raw types
List<TypeProjection> arguments = Collections.<TypeProjection>emptyList(); // TODO
return new TypeImpl(
Collections.<Attribute>emptyList(),
descriptor.getTypeConstructor(),
true,
arguments,
descriptor.getMemberScope(arguments));
}
@Override
@@ -42,10 +56,10 @@ public class JavaTypeTransformer {
@Override
public Type visitArrayType(PsiArrayType arrayType) {
return JetStandardClasses.getUnitType(); // TODO!!!
Type type = transform(arrayType.getComponentType());
return TypeUtils.makeNullable(standardLibrary.getArrayType(type));
}
});
return result;
}
public Map<String, Type> getPrimitiveTypesMap() {
@@ -1,5 +1,7 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.jet.resolve.DescriptorUtil;
import java.util.List;
/**
@@ -28,4 +30,9 @@ public abstract class DeclarationDescriptorImpl extends AnnotatedImpl implements
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
accept(visitor, null);
}
@Override
public String toString() {
return DescriptorUtil.renderPresentableText(this) + "[" + getClass().getCanonicalName()+ "]";
}
}
@@ -10,9 +10,57 @@ import java.util.*;
*/
public class JetTypeChecker {
public static final JetTypeChecker INSTANCE = new JetTypeChecker();
private final Map<TypeConstructor, Set<TypeConstructor>> conversionMap = new HashMap<TypeConstructor, Set<TypeConstructor>>();
private final JetStandardLibrary standardLibrary;
private JetTypeChecker() {}
public JetTypeChecker(JetStandardLibrary standardLibrary) {
this.standardLibrary = standardLibrary;
}
private Map<TypeConstructor, Set<TypeConstructor>> getConversionMap() {
if (conversionMap.size() == 0) {
addConversion(standardLibrary.getByte(),
standardLibrary.getShort(),
standardLibrary.getInt(),
standardLibrary.getLong(),
standardLibrary.getFloat(),
standardLibrary.getDouble());
addConversion(standardLibrary.getShort(),
standardLibrary.getInt(),
standardLibrary.getLong(),
standardLibrary.getFloat(),
standardLibrary.getDouble());
addConversion(standardLibrary.getChar(),
standardLibrary.getInt(),
standardLibrary.getLong(),
standardLibrary.getFloat(),
standardLibrary.getDouble());
addConversion(standardLibrary.getInt(),
standardLibrary.getLong(),
standardLibrary.getFloat(),
standardLibrary.getDouble());
addConversion(standardLibrary.getLong(),
standardLibrary.getFloat(),
standardLibrary.getDouble());
addConversion(standardLibrary.getFloat(),
standardLibrary.getDouble());
}
return conversionMap;
}
private void addConversion(ClassDescriptor actual, ClassDescriptor... convertedTo) {
TypeConstructor[] constructors = new TypeConstructor[convertedTo.length];
for (int i = 0, convertedToLength = convertedTo.length; i < convertedToLength; i++) {
ClassDescriptor classDescriptor = convertedTo[i];
constructors[i] = classDescriptor.getTypeConstructor();
}
conversionMap.put(actual.getTypeConstructor(), new HashSet<TypeConstructor>(Arrays.asList(constructors)));
}
public Type commonSupertype(Collection<Type> types) {
Collection<Type> typeSet = new HashSet<Type>(types);
@@ -121,7 +169,7 @@ public class JetTypeChecker {
if (ins != null) {
Variance projectionKind = variance == Variance.IN_VARIANCE ? Variance.INVARIANT : Variance.IN_VARIANCE;
Type intersection = TypeUtils.intersect(ins);
Type intersection = TypeUtils.intersect(this, ins);
if (intersection == null) {
return new TypeProjection(Variance.OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds()));
}
@@ -230,8 +278,19 @@ public class JetTypeChecker {
}
public boolean isConvertibleTo(Type actual, Type expected) {
// TODO
return isSubtypeOf(actual, expected);
if (isSubtypeOf(actual, expected)) return true;
if (expected.getConstructor() == JetStandardClasses.getTuple(0).getTypeConstructor()) {
return true;
}
if (actual.getArguments().isEmpty()) {
TypeConstructor actualConstructor = actual.getConstructor();
TypeConstructor constructor = expected.getConstructor();
Set<TypeConstructor> convertibleTo = getConversionMap().get(actualConstructor);
if (convertibleTo != null) {
return convertibleTo.contains(constructor);
}
}
return false;
}
public boolean isSubtypeOf(Type subtype, Type supertype) {
@@ -170,13 +170,12 @@ public class JetTypeInferrer {
if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.COLON) {
Type actualType = getType(scope, expression.getLeft(), false);
Type expectedType = typeResolver.resolveType(scope, expression.getRight());
if (JetTypeChecker.INSTANCE.isSubtypeOf(actualType, expectedType)) {
result[0] = expectedType;
return;
} else {
// TODO
throw new UnsupportedOperationException("Type mismatch: expected " + expectedType + " but found " + actualType);
if (!semanticServices.getTypeChecker().isSubtypeOf(actualType, expectedType)) {
// TODO
semanticServices.getErrorHandler().typeMismatch(expression.getLeft(), expectedType, actualType);
}
result[0] = expectedType;
return;
}
throw new UnsupportedOperationException(); // TODO
}
@@ -192,7 +191,7 @@ public class JetTypeInferrer {
} else {
Type thenType = getType(scope, expression.getThen(), true);
Type elseType = getType(scope, elseBranch, true);
result[0] = JetTypeChecker.INSTANCE.commonSupertype(Arrays.asList(thenType, elseType));
result[0] = semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType));
}
}
@@ -201,7 +200,7 @@ public class JetTypeInferrer {
// TODO :change scope according to the bound value in the when header
List<Type> expressions = new ArrayList<Type>();
collectAllReturnTypes(expression, scope, expressions);
result[0] = JetTypeChecker.INSTANCE.commonSupertype(expressions);
result[0] = semanticServices.getTypeChecker().commonSupertype(expressions);
}
@Override
@@ -219,7 +218,7 @@ public class JetTypeInferrer {
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
}
types.add(getType(scope, tryBlock, true));
result[0] = JetTypeChecker.INSTANCE.commonSupertype(types);
result[0] = semanticServices.getTypeChecker().commonSupertype(types);
}
@Override
@@ -366,8 +365,11 @@ public class JetTypeInferrer {
JetExpression left = expression.getLeft();
Type leftType = getType(scope, left, false);
JetExpression right = expression.getRight();
if (right == null) {
return ErrorType.createErrorType("No right argument");
}
Type rightType = getType(scope, right, false);
OverloadDomain overloadDomain = OverloadResolver.INSTANCE.getOverloadDomain(leftType, scope, name);
OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(leftType, scope, name);
overloadDomain = wrapForTracing(overloadDomain, operationSign);
FunctionDescriptor functionDescriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.<Type>emptyList(), Collections.singletonList(rightType));
if (functionDescriptor != null) {
@@ -409,7 +411,7 @@ public class JetTypeInferrer {
Type receiverType = getType(scope, expression.getReceiverExpression(), false);
if (receiverType != null) {
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
reference[0] = referenceExpression;
}
} else {
@@ -420,7 +422,7 @@ public class JetTypeInferrer {
@Override
public void visitReferenceExpression(JetReferenceExpression expression) {
// a -- create a hierarchical lookup domain for this.a
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(null, scope, expression.getReferencedName());
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(null, scope, expression.getReferencedName());
reference[0] = expression;
}
@@ -18,8 +18,15 @@ public class TypeUtils {
return new TypeImpl(type.getAttributes(), type.getConstructor(), true, type.getArguments(), type.getMemberScope());
}
public static Type makeNotNullable(Type type) {
if (!type.isNullable()) {
return type;
}
return new TypeImpl(type.getAttributes(), type.getConstructor(), false, type.getArguments(), type.getMemberScope());
}
@Nullable
public static Type intersect(Set<Type> types) {
public static Type intersect(JetTypeChecker typeChecker, Set<Type> types) {
assert !types.isEmpty();
if (types.size() == 1) {
@@ -31,9 +38,9 @@ public class TypeUtils {
for (Iterator<Type> iterator = types.iterator(); iterator.hasNext();) {
Type type = iterator.next();
if (!canHaveSubtypes(type)) {
if (!canHaveSubtypes(typeChecker, type)) {
for (Type other : types) {
if (type != other || !JetTypeChecker.INSTANCE.isSubtypeOf(type, other)) {
if (type != other || !typeChecker.isSubtypeOf(type, other)) {
return null;
}
}
@@ -58,7 +65,7 @@ public class TypeUtils {
JetStandardClasses.STUB);
}
private static boolean canHaveSubtypes(Type type) {
private static boolean canHaveSubtypes(JetTypeChecker typeChecker, Type type) {
if (type.isNullable()) {
return true;
}
@@ -78,17 +85,17 @@ public class TypeUtils {
case INVARIANT:
switch (projectionKind) {
case INVARIANT:
if (lowerThanBound(argument, parameterDescriptor) || canHaveSubtypes(argument)) {
if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
return true;
}
break;
case IN_VARIANCE:
if (lowerThanBound(argument, parameterDescriptor)) {
if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
return true;
}
break;
case OUT_VARIANCE:
if (canHaveSubtypes(argument)) {
if (canHaveSubtypes(typeChecker, argument)) {
return true;
}
break;
@@ -96,22 +103,22 @@ public class TypeUtils {
break;
case IN_VARIANCE:
if (projectionKind != Variance.OUT_VARIANCE) {
if (lowerThanBound(argument, parameterDescriptor)) {
if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
return true;
}
} else {
if (canHaveSubtypes(argument)) {
if (canHaveSubtypes(typeChecker, argument)) {
return true;
}
}
break;
case OUT_VARIANCE:
if (projectionKind != Variance.IN_VARIANCE) {
if (canHaveSubtypes(argument)) {
if (canHaveSubtypes(typeChecker, argument)) {
return true;
}
} else {
if (lowerThanBound(argument, parameterDescriptor)) {
if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
return true;
}
}
@@ -121,9 +128,9 @@ public class TypeUtils {
return false;
}
private static boolean lowerThanBound(Type argument, TypeParameterDescriptor parameterDescriptor) {
private static boolean lowerThanBound(JetTypeChecker typeChecker, Type argument, TypeParameterDescriptor parameterDescriptor) {
for (Type bound : parameterDescriptor.getUpperBounds()) {
if (JetTypeChecker.INSTANCE.isSubtypeOf(argument, bound)) {
if (typeChecker.isSubtypeOf(argument, bound)) {
if (!argument.getConstructor().equals(bound.getConstructor())) {
return true;
}
+14 -1
View File
@@ -33,4 +33,17 @@ class B : `java::java.lang.Object`Object {
fun barrr() : `std::Int`Int {
`foo`foo(new `A`A())
}
}
}
~c~fun c(~x~x : `java::java.lang.Number`Number) {
`x`x.`java::java.lang.Number.intValue()`intValue()
}
fun <T> t(t : T) : T {
`c`c(new java.lang.Integer(1))
System.out.`java::java.io.PrintStream.print(Object)`print(t)
System.out.`java::java.io.PrintStream.print(char[])`print(null : Array<Char>?)
System.out.`java::java.io.PrintStream.print(Object)`print(null : Object?)
System.out.`java::java.io.PrintStream.print(Int)`print(1)
System.out.`java::java.io.PrintStream.print(Double)`print(1.0)
}
@@ -36,18 +36,25 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
nameToDescriptor.put("std::Array.set(Int, Int)", descriptorForSet.getOriginal());
Map<String,PsiElement> nameToDeclaration = new HashMap<String, PsiElement>();
nameToDeclaration.put("java::java.util.Collections.emptyList()", findMethod(findClass("java.util.Collections"), "emptyList"));
nameToDeclaration.put("java::java.util.Collections", findClass("java.util.Collections"));
PsiClass java_util_Collections = findClass("java.util.Collections");
nameToDeclaration.put("java::java.util.Collections.emptyList()", findMethod(java_util_Collections, "emptyList"));
nameToDeclaration.put("java::java.util.Collections", java_util_Collections);
nameToDeclaration.put("java::java.util.List", findClass("java.util.List"));
nameToDeclaration.put("java::java", findPackage("java"));
nameToDeclaration.put("java::java.util", findPackage("java.util"));
nameToDeclaration.put("java::java.lang", findPackage("java.lang"));
nameToDeclaration.put("java::java.lang.Object", findClass("java.lang.Object"));
nameToDeclaration.put("java::java.lang.System", findClass("java.lang.System"));
PsiClass java_lang_System = findClass("java.lang.System");
nameToDeclaration.put("java::java.lang.System", java_lang_System);
PsiMethod[] methods = findClass("java.io.PrintStream").findMethodsByName("print", true);
nameToDeclaration.put("java::java.io.PrintStream.print(Object)", methods[8]);
nameToDeclaration.put("java::java.io.PrintStream.print(Int)", methods[2]);
nameToDeclaration.put("java::java.lang.System.out", findClass("java.lang.System").findFieldByName("out", true));
nameToDeclaration.put("java::java.io.PrintStream.print(char[])", methods[6]);
nameToDeclaration.put("java::java.io.PrintStream.print(Double)", methods[5]);
nameToDeclaration.put("java::java.lang.System.out", java_lang_System.findFieldByName("out", true));
PsiClass java_lang_Number = findClass("java.lang.Number");
nameToDeclaration.put("java::java.lang.Number", java_lang_Number);
nameToDeclaration.put("java::java.lang.Number.intValue()", java_lang_Number.findMethodsByName("intValue", true)[0]);
return new ExpectedResolveData(nameToDescriptor, nameToDeclaration);
}
@@ -342,7 +342,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertType("new Functions<String>().f()", "Unit");
assertType("new Functions<String>().f(1)", "Int");
assertType("new Functions<String>().f(1d)", (String) null);
assertType("new Functions<Double>().f(())", "Double");
assertType("new Functions<Double>().f((1, 1))", "Double");
assertType("new Functions<Double>().f(1d)", "Any");
assertType("new Functions<Byte>().f<String>(\"\")", "Byte");
assertType("new Functions<Byte>().f<String>(1)", (String) null);
@@ -418,14 +418,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
for (String type : types) {
subtypes.add(makeType(type));
}
Type result = JetTypeChecker.INSTANCE.commonSupertype(subtypes);
Type result = semanticServices.getTypeChecker().commonSupertype(subtypes);
assertTrue(result + " != " + expected, TypeImpl.equalTypes(result, makeType(expected)));
}
private void assertSubtypingRelation(String type1, String type2, boolean expected) {
Type typeNode1 = makeType(type1);
Type typeNode2 = makeType(type2);
boolean result = JetTypeChecker.INSTANCE.isSubtypeOf(
boolean result = semanticServices.getTypeChecker().isSubtypeOf(
typeNode1,
typeNode2);
String modifier = expected ? "not " : "";
@@ -436,14 +436,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertTrue(
expression + " must be convertible to " + type,
JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type));
semanticServices.getTypeChecker().isConvertibleTo(jetExpression, type));
}
private void assertNotConvertibleTo(String expression, Type type) {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertFalse(
expression + " must not be convertible to " + type,
JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type));
semanticServices.getTypeChecker().isConvertibleTo(jetExpression, type));
}
private void assertType(String expression, Type expectedType) {
@@ -509,7 +509,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
"fun f() : Unit {} " +
"fun f(a : Int) : Int {} " +
"fun f(a : T) : Any {} " +
"fun f(a : Unit) : T {} " +
"fun f(a : (Int, Int)) : T {} " +
"fun f<E>(a : E) : T {} " +
"}"
};