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; package org.jetbrains.jet.lang;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.types.Type;
/** /**
* @author abreslav * @author abreslav
@@ -18,6 +20,11 @@ public class ErrorHandler {
public void structuralError(ASTNode node, String errorMessage) { public void structuralError(ASTNode node, String errorMessage) {
throw new IllegalStateException(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) { public void unresolvedReference(JetReferenceExpression referenceExpression) {
@@ -25,4 +32,7 @@ public class ErrorHandler {
public void structuralError(ASTNode node, String errorMessage) { 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; package org.jetbrains.jet.lang;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver; 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.BindingTrace;
import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lang.types.JetTypeInferrer; import org.jetbrains.jet.lang.types.JetTypeInferrer;
/** /**
@@ -20,6 +23,8 @@ public class JetSemanticServices {
private final JetTypeInferrer typeInferrer; private final JetTypeInferrer typeInferrer;
private final JetStandardLibrary standardLibrary; private final JetStandardLibrary standardLibrary;
private final JetTypeChecker typeChecker;
private final OverloadResolver overloadResolver;
private final ErrorHandler errorHandler; private final ErrorHandler errorHandler;
@@ -27,25 +32,42 @@ public class JetSemanticServices {
this.standardLibrary = standardLibrary; this.standardLibrary = standardLibrary;
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
this.typeInferrer = new JetTypeInferrer(BindingTrace.DUMMY, this); this.typeInferrer = new JetTypeInferrer(BindingTrace.DUMMY, this);
this.typeChecker = new JetTypeChecker(standardLibrary);
this.overloadResolver = new OverloadResolver(typeChecker);
} }
@NotNull
public JetStandardLibrary getStandardLibrary() { public JetStandardLibrary getStandardLibrary() {
return standardLibrary; return standardLibrary;
} }
@NotNull
public JetTypeInferrer getTypeInferrer() { public JetTypeInferrer getTypeInferrer() {
return typeInferrer; return typeInferrer;
} }
@NotNull
public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) { public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) {
return new ClassDescriptorResolver(this, trace); return new ClassDescriptorResolver(this, trace);
} }
@NotNull
public JetTypeInferrer getTypeInferrer(BindingTrace trace) { public JetTypeInferrer getTypeInferrer(BindingTrace trace) {
return new JetTypeInferrer(trace, this); return new JetTypeInferrer(trace, this);
} }
@NotNull
public ErrorHandler getErrorHandler() { public ErrorHandler getErrorHandler() {
return errorHandler; return errorHandler;
} }
@NotNull
public JetTypeChecker getTypeChecker() {
return typeChecker;
}
@NotNull
public OverloadResolver getOverloadResolver() {
return overloadResolver;
}
} }
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.annotations; package org.jetbrains.jet.lang.annotations;
import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator; import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
@@ -29,6 +30,16 @@ public class JetPsiChecker implements Annotator {
public void unresolvedReference(JetReferenceExpression referenceExpression) { public void unresolvedReference(JetReferenceExpression referenceExpression) {
holder.createErrorAnnotation(referenceExpression, "Unresolved"); 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() { file.getRootNamespace().accept(new JetVisitor() {
@Override @Override
@@ -4,19 +4,18 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/** /**
* @author abreslav * @author abreslav
*/ */
public class OverloadResolver { public class OverloadResolver {
public static final OverloadResolver INSTANCE = new OverloadResolver(); private final JetTypeChecker typeChecker;
private OverloadResolver() {} public OverloadResolver(JetTypeChecker typeChecker) {
this.typeChecker = typeChecker;
}
@NotNull @NotNull
public OverloadDomain getOverloadDomain(Type receiverType, @NotNull JetScope outerScope, @NotNull String name) { public OverloadDomain getOverloadDomain(Type receiverType, @NotNull JetScope outerScope, @NotNull String name) {
@@ -54,7 +53,7 @@ public class OverloadResolver {
Type argumentType = positionedValueArgumentTypes.get(i); Type argumentType = positionedValueArgumentTypes.get(i);
Type parameterType = parameters.get(i).getType(); Type parameterType = parameters.get(i).getType();
// TODO : handle vararg cases here // TODO : handle vararg cases here
if (!JetTypeChecker.INSTANCE.isConvertibleTo(argumentType, parameterType)) { if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
continue descLoop; continue descLoop;
} }
} }
@@ -64,14 +63,14 @@ public class OverloadResolver {
for (int i = 0; i < nonVarargs; i++) { for (int i = 0; i < nonVarargs; i++) {
Type argumentType = positionedValueArgumentTypes.get(i); Type argumentType = positionedValueArgumentTypes.get(i);
Type parameterType = parameters.get(i).getType(); Type parameterType = parameters.get(i).getType();
if (!JetTypeChecker.INSTANCE.isConvertibleTo(argumentType, parameterType)) { if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
continue descLoop; continue descLoop;
} }
} }
Type varArgType = parameters.get(nonVarargs).getType(); Type varArgType = parameters.get(nonVarargs).getType();
for (int i = nonVarargs, args = positionedValueArgumentTypes.size(); i < args; i++) { for (int i = nonVarargs, args = positionedValueArgumentTypes.size(); i < args; i++) {
Type argumentType = positionedValueArgumentTypes.get(i); Type argumentType = positionedValueArgumentTypes.get(i);
if (!JetTypeChecker.INSTANCE.isConvertibleTo(argumentType, varArgType)) { if (!typeChecker.isConvertibleTo(argumentType, varArgType)) {
continue descLoop; continue descLoop;
} }
} }
@@ -84,6 +83,23 @@ public class OverloadResolver {
} else if (applicable.size() == 1) { } else if (applicable.size() == 1) {
return applicable.get(0); return applicable.get(0);
} else { } 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(); 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) { private Type resolveTypeElement(final JetScope scope, final List<Attribute> attributes, JetTypeElement typeElement, final boolean nullable) {
final Type[] result = new Type[1]; final Type[] result = new Type[1];
typeElement.accept(new JetVisitor() { if (typeElement != null) {
@Override typeElement.accept(new JetVisitor() {
public void visitUserType(JetUserType type) { @Override
ClassDescriptor classDescriptor = resolveClass(scope, type); public void visitUserType(JetUserType type) {
if (classDescriptor != null) { ClassDescriptor classDescriptor = resolveClass(scope, type);
trace.recordReferenceResolution(type.getReferenceExpression(), classDescriptor); if (classDescriptor != null) {
TypeConstructor typeConstructor = classDescriptor.getTypeConstructor(); trace.recordReferenceResolution(type.getReferenceExpression(), classDescriptor);
List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments()); TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
result[0] = new TypeImpl( List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments());
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);
result[0] = new TypeImpl( result[0] = new TypeImpl(
attributes, attributes,
typeParameterDescriptor.getTypeConstructor(), typeConstructor,
nullable || hasNullableBound(typeParameterDescriptor), nullable,
Collections.<TypeProjection>emptyList(), arguments,
// TODO : joint domain classDescriptor.getMemberScope(arguments)
JetStandardClasses.STUB
); );
} 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()); semanticServices.getErrorHandler().unresolvedReference(type.getReferenceExpression());
} }
} }
else {
semanticServices.getErrorHandler().unresolvedReference(type.getReferenceExpression());
}
}
@Override @Override
public void visitNullableType(JetNullableType nullableType) { public void visitNullableType(JetNullableType nullableType) {
result[0] = resolveTypeElement(scope, attributes, nullableType.getInnerType(), true); 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()));
} }
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 List<Type> parameterTypes = new ArrayList<Type>();
public void visitJetElement(JetElement elem) { for (JetParameter parameter : type.getParameters()) {
throw new IllegalArgumentException("Unsupported type: " + elem); 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) { if (result[0] == null) {
return ErrorType.createErrorType(typeElement.getText()); return ErrorType.createErrorType(typeElement == null ? "No type element": typeElement.getText());
} }
return result[0]; return result[0];
} }
@@ -137,7 +139,7 @@ public class TypeResolver {
Type type; Type type;
if (projectionKind == JetProjectionKind.STAR) { if (projectionKind == JetProjectionKind.STAR) {
Set<Type> upperBounds = constructor.getParameters().get(i).getUpperBounds(); 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 { else {
// TODO : handle the Foo<in *> case // TODO : handle the Foo<in *> case
@@ -61,6 +61,6 @@ public class WritableFunctionGroup implements FunctionGroup {
@Override @Override
public boolean isEmpty() { 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) { public void addClassAlias(String name, ClassDescriptor classDescriptor) {
Map<String, ClassDescriptor> classDescriptors = getClassDescriptors(); Map<String, ClassDescriptor> classDescriptors = getClassDescriptors();
if (classDescriptors.put(name, classDescriptor) != null) { if (classDescriptors.put(name, classDescriptor) != null) {
throw new UnsupportedOperationException("Class redeclared: " + classDescriptor.getName()); throw new UnsupportedOperationException("Class redeclared: " + classDescriptor.getName());
} }
} }
@@ -72,22 +72,22 @@ public class JavaClassMembersScope implements JetScope {
@Override @Override
public ExtensionDescriptor getExtension(@NotNull String name) { public ExtensionDescriptor getExtension(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO return null;
} }
@Override @Override
public NamespaceDescriptor getNamespace(@NotNull String name) { public NamespaceDescriptor getNamespace(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO return null;
} }
@Override @Override
public TypeParameterDescriptor getTypeParameter(@NotNull String name) { public TypeParameterDescriptor getTypeParameter(@NotNull String name) {
throw new UnsupportedOperationException(); // TODO return null;
} }
@NotNull @NotNull
@Override @Override
public Type getThisType() { public Type getThisType() {
throw new UnsupportedOperationException(); // TODO return null;
} }
} }
@@ -59,13 +59,29 @@ public class JavaDescriptorResolver {
modifierList == null ? false : modifierList.hasModifierProperty(PsiModifier.FINAL), modifierList == null ? false : modifierList.hasModifierProperty(PsiModifier.FINAL),
name, name,
Collections.<TypeParameterDescriptor>emptyList(), Collections.<TypeParameterDescriptor>emptyList(),
Collections.<Type>emptyList(), getSupertypes(psiClass),
new JavaClassMembersScope(psiClass, semanticServices, false) new JavaClassMembersScope(psiClass, semanticServices, false)
); );
semanticServices.getTrace().recordDeclarationResolution(psiClass, classDescriptor); semanticServices.getTrace().recordDeclarationResolution(psiClass, classDescriptor);
return 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) { public NamespaceDescriptor resolveNamespace(String qualifiedName) {
NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(qualifiedName); NamespaceDescriptor namespaceDescriptor = namespaceDescriptorCache.get(qualifiedName);
if (namespaceDescriptor == null) { if (namespaceDescriptor == null) {
@@ -4,7 +4,9 @@ import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -23,13 +25,25 @@ public class JavaTypeTransformer {
@NotNull @NotNull
public Type transform(PsiType javaType) { public Type transform(PsiType javaType) {
Type result = javaType.accept(new PsiTypeVisitor<Type>() { return javaType.accept(new PsiTypeVisitor<Type>() {
@Override @Override
public Type visitClassType(PsiClassType classType) { public Type visitClassType(PsiClassType classType) {
PsiClass psiClass = classType.resolveGenerics().getElement(); 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); ClassDescriptor descriptor = resolver.resolveClass(psiClass);
// TODO : parameters // TODO : arguments & raw types
return new TypeImpl(descriptor); List<TypeProjection> arguments = Collections.<TypeProjection>emptyList(); // TODO
return new TypeImpl(
Collections.<Attribute>emptyList(),
descriptor.getTypeConstructor(),
true,
arguments,
descriptor.getMemberScope(arguments));
} }
@Override @Override
@@ -42,10 +56,10 @@ public class JavaTypeTransformer {
@Override @Override
public Type visitArrayType(PsiArrayType arrayType) { 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() { public Map<String, Type> getPrimitiveTypesMap() {
@@ -1,5 +1,7 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.jet.resolve.DescriptorUtil;
import java.util.List; import java.util.List;
/** /**
@@ -28,4 +30,9 @@ public abstract class DeclarationDescriptorImpl extends AnnotatedImpl implements
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) { public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
accept(visitor, null); accept(visitor, null);
} }
@Override
public String toString() {
return DescriptorUtil.renderPresentableText(this) + "[" + getClass().getCanonicalName()+ "]";
}
} }
@@ -10,9 +10,57 @@ import java.util.*;
*/ */
public class JetTypeChecker { 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) { public Type commonSupertype(Collection<Type> types) {
Collection<Type> typeSet = new HashSet<Type>(types); Collection<Type> typeSet = new HashSet<Type>(types);
@@ -121,7 +169,7 @@ public class JetTypeChecker {
if (ins != null) { if (ins != null) {
Variance projectionKind = variance == Variance.IN_VARIANCE ? Variance.INVARIANT : Variance.IN_VARIANCE; 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) { if (intersection == null) {
return new TypeProjection(Variance.OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds())); return new TypeProjection(Variance.OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds()));
} }
@@ -230,8 +278,19 @@ public class JetTypeChecker {
} }
public boolean isConvertibleTo(Type actual, Type expected) { public boolean isConvertibleTo(Type actual, Type expected) {
// TODO if (isSubtypeOf(actual, expected)) return true;
return isSubtypeOf(actual, expected); 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) { public boolean isSubtypeOf(Type subtype, Type supertype) {
@@ -170,13 +170,12 @@ public class JetTypeInferrer {
if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.COLON) { if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.COLON) {
Type actualType = getType(scope, expression.getLeft(), false); Type actualType = getType(scope, expression.getLeft(), false);
Type expectedType = typeResolver.resolveType(scope, expression.getRight()); Type expectedType = typeResolver.resolveType(scope, expression.getRight());
if (JetTypeChecker.INSTANCE.isSubtypeOf(actualType, expectedType)) { if (!semanticServices.getTypeChecker().isSubtypeOf(actualType, expectedType)) {
result[0] = expectedType; // TODO
return; semanticServices.getErrorHandler().typeMismatch(expression.getLeft(), expectedType, actualType);
} else {
// TODO
throw new UnsupportedOperationException("Type mismatch: expected " + expectedType + " but found " + actualType);
} }
result[0] = expectedType;
return;
} }
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
@@ -192,7 +191,7 @@ public class JetTypeInferrer {
} else { } else {
Type thenType = getType(scope, expression.getThen(), true); Type thenType = getType(scope, expression.getThen(), true);
Type elseType = getType(scope, elseBranch, 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 // TODO :change scope according to the bound value in the when header
List<Type> expressions = new ArrayList<Type>(); List<Type> expressions = new ArrayList<Type>();
collectAllReturnTypes(expression, scope, expressions); collectAllReturnTypes(expression, scope, expressions);
result[0] = JetTypeChecker.INSTANCE.commonSupertype(expressions); result[0] = semanticServices.getTypeChecker().commonSupertype(expressions);
} }
@Override @Override
@@ -219,7 +218,7 @@ public class JetTypeInferrer {
types.add(getType(scope, finallyBlock.getFinalExpression(), true)); types.add(getType(scope, finallyBlock.getFinalExpression(), true));
} }
types.add(getType(scope, tryBlock, true)); types.add(getType(scope, tryBlock, true));
result[0] = JetTypeChecker.INSTANCE.commonSupertype(types); result[0] = semanticServices.getTypeChecker().commonSupertype(types);
} }
@Override @Override
@@ -366,8 +365,11 @@ public class JetTypeInferrer {
JetExpression left = expression.getLeft(); JetExpression left = expression.getLeft();
Type leftType = getType(scope, left, false); Type leftType = getType(scope, left, false);
JetExpression right = expression.getRight(); JetExpression right = expression.getRight();
if (right == null) {
return ErrorType.createErrorType("No right argument");
}
Type rightType = getType(scope, right, false); 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); overloadDomain = wrapForTracing(overloadDomain, operationSign);
FunctionDescriptor functionDescriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.<Type>emptyList(), Collections.singletonList(rightType)); FunctionDescriptor functionDescriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.<Type>emptyList(), Collections.singletonList(rightType));
if (functionDescriptor != null) { if (functionDescriptor != null) {
@@ -409,7 +411,7 @@ public class JetTypeInferrer {
Type receiverType = getType(scope, expression.getReceiverExpression(), false); Type receiverType = getType(scope, expression.getReceiverExpression(), false);
if (receiverType != null) { if (receiverType != null) {
result[0] = OverloadResolver.INSTANCE.getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName()); result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referenceExpression.getReferencedName());
reference[0] = referenceExpression; reference[0] = referenceExpression;
} }
} else { } else {
@@ -420,7 +422,7 @@ public class JetTypeInferrer {
@Override @Override
public void visitReferenceExpression(JetReferenceExpression expression) { public void visitReferenceExpression(JetReferenceExpression expression) {
// a -- create a hierarchical lookup domain for this.a // 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; reference[0] = expression;
} }
@@ -18,8 +18,15 @@ public class TypeUtils {
return new TypeImpl(type.getAttributes(), type.getConstructor(), true, type.getArguments(), type.getMemberScope()); 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 @Nullable
public static Type intersect(Set<Type> types) { public static Type intersect(JetTypeChecker typeChecker, Set<Type> types) {
assert !types.isEmpty(); assert !types.isEmpty();
if (types.size() == 1) { if (types.size() == 1) {
@@ -31,9 +38,9 @@ public class TypeUtils {
for (Iterator<Type> iterator = types.iterator(); iterator.hasNext();) { for (Iterator<Type> iterator = types.iterator(); iterator.hasNext();) {
Type type = iterator.next(); Type type = iterator.next();
if (!canHaveSubtypes(type)) { if (!canHaveSubtypes(typeChecker, type)) {
for (Type other : types) { for (Type other : types) {
if (type != other || !JetTypeChecker.INSTANCE.isSubtypeOf(type, other)) { if (type != other || !typeChecker.isSubtypeOf(type, other)) {
return null; return null;
} }
} }
@@ -58,7 +65,7 @@ public class TypeUtils {
JetStandardClasses.STUB); JetStandardClasses.STUB);
} }
private static boolean canHaveSubtypes(Type type) { private static boolean canHaveSubtypes(JetTypeChecker typeChecker, Type type) {
if (type.isNullable()) { if (type.isNullable()) {
return true; return true;
} }
@@ -78,17 +85,17 @@ public class TypeUtils {
case INVARIANT: case INVARIANT:
switch (projectionKind) { switch (projectionKind) {
case INVARIANT: case INVARIANT:
if (lowerThanBound(argument, parameterDescriptor) || canHaveSubtypes(argument)) { if (lowerThanBound(typeChecker, argument, parameterDescriptor) || canHaveSubtypes(typeChecker, argument)) {
return true; return true;
} }
break; break;
case IN_VARIANCE: case IN_VARIANCE:
if (lowerThanBound(argument, parameterDescriptor)) { if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
return true; return true;
} }
break; break;
case OUT_VARIANCE: case OUT_VARIANCE:
if (canHaveSubtypes(argument)) { if (canHaveSubtypes(typeChecker, argument)) {
return true; return true;
} }
break; break;
@@ -96,22 +103,22 @@ public class TypeUtils {
break; break;
case IN_VARIANCE: case IN_VARIANCE:
if (projectionKind != Variance.OUT_VARIANCE) { if (projectionKind != Variance.OUT_VARIANCE) {
if (lowerThanBound(argument, parameterDescriptor)) { if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
return true; return true;
} }
} else { } else {
if (canHaveSubtypes(argument)) { if (canHaveSubtypes(typeChecker, argument)) {
return true; return true;
} }
} }
break; break;
case OUT_VARIANCE: case OUT_VARIANCE:
if (projectionKind != Variance.IN_VARIANCE) { if (projectionKind != Variance.IN_VARIANCE) {
if (canHaveSubtypes(argument)) { if (canHaveSubtypes(typeChecker, argument)) {
return true; return true;
} }
} else { } else {
if (lowerThanBound(argument, parameterDescriptor)) { if (lowerThanBound(typeChecker, argument, parameterDescriptor)) {
return true; return true;
} }
} }
@@ -121,9 +128,9 @@ public class TypeUtils {
return false; 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()) { for (Type bound : parameterDescriptor.getUpperBounds()) {
if (JetTypeChecker.INSTANCE.isSubtypeOf(argument, bound)) { if (typeChecker.isSubtypeOf(argument, bound)) {
if (!argument.getConstructor().equals(bound.getConstructor())) { if (!argument.getConstructor().equals(bound.getConstructor())) {
return true; return true;
} }
+14 -1
View File
@@ -33,4 +33,17 @@ class B : `java::java.lang.Object`Object {
fun barrr() : `std::Int`Int { fun barrr() : `std::Int`Int {
`foo`foo(new `A`A()) `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()); nameToDescriptor.put("std::Array.set(Int, Int)", descriptorForSet.getOriginal());
Map<String,PsiElement> nameToDeclaration = new HashMap<String, PsiElement>(); Map<String,PsiElement> nameToDeclaration = new HashMap<String, PsiElement>();
nameToDeclaration.put("java::java.util.Collections.emptyList()", findMethod(findClass("java.util.Collections"), "emptyList")); PsiClass java_util_Collections = findClass("java.util.Collections");
nameToDeclaration.put("java::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.util.List", findClass("java.util.List"));
nameToDeclaration.put("java::java", findPackage("java")); nameToDeclaration.put("java::java", findPackage("java"));
nameToDeclaration.put("java::java.util", findPackage("java.util")); nameToDeclaration.put("java::java.util", findPackage("java.util"));
nameToDeclaration.put("java::java.lang", findPackage("java.lang")); nameToDeclaration.put("java::java.lang", findPackage("java.lang"));
nameToDeclaration.put("java::java.lang.Object", findClass("java.lang.Object")); 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); 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(Object)", methods[8]);
nameToDeclaration.put("java::java.io.PrintStream.print(Int)", methods[2]); 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); 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()", "Unit");
assertType("new Functions<String>().f(1)", "Int"); assertType("new Functions<String>().f(1)", "Int");
assertType("new Functions<String>().f(1d)", (String) null); 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<Double>().f(1d)", "Any");
assertType("new Functions<Byte>().f<String>(\"\")", "Byte"); assertType("new Functions<Byte>().f<String>(\"\")", "Byte");
assertType("new Functions<Byte>().f<String>(1)", (String) null); assertType("new Functions<Byte>().f<String>(1)", (String) null);
@@ -418,14 +418,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
for (String type : types) { for (String type : types) {
subtypes.add(makeType(type)); subtypes.add(makeType(type));
} }
Type result = JetTypeChecker.INSTANCE.commonSupertype(subtypes); Type result = semanticServices.getTypeChecker().commonSupertype(subtypes);
assertTrue(result + " != " + expected, TypeImpl.equalTypes(result, makeType(expected))); assertTrue(result + " != " + expected, TypeImpl.equalTypes(result, makeType(expected)));
} }
private void assertSubtypingRelation(String type1, String type2, boolean expected) { private void assertSubtypingRelation(String type1, String type2, boolean expected) {
Type typeNode1 = makeType(type1); Type typeNode1 = makeType(type1);
Type typeNode2 = makeType(type2); Type typeNode2 = makeType(type2);
boolean result = JetTypeChecker.INSTANCE.isSubtypeOf( boolean result = semanticServices.getTypeChecker().isSubtypeOf(
typeNode1, typeNode1,
typeNode2); typeNode2);
String modifier = expected ? "not " : ""; String modifier = expected ? "not " : "";
@@ -436,14 +436,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression); JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertTrue( assertTrue(
expression + " must be convertible to " + type, expression + " must be convertible to " + type,
JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type)); semanticServices.getTypeChecker().isConvertibleTo(jetExpression, type));
} }
private void assertNotConvertibleTo(String expression, Type type) { private void assertNotConvertibleTo(String expression, Type type) {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression); JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertFalse( assertFalse(
expression + " must not be convertible to " + type, expression + " must not be convertible to " + type,
JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type)); semanticServices.getTypeChecker().isConvertibleTo(jetExpression, type));
} }
private void assertType(String expression, Type expectedType) { private void assertType(String expression, Type expectedType) {
@@ -509,7 +509,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
"fun f() : Unit {} " + "fun f() : Unit {} " +
"fun f(a : Int) : Int {} " + "fun f(a : Int) : Int {} " +
"fun f(a : T) : Any {} " + "fun f(a : T) : Any {} " +
"fun f(a : Unit) : T {} " + "fun f(a : (Int, Int)) : T {} " +
"fun f<E>(a : E) : T {} " + "fun f<E>(a : E) : T {} " +
"}" "}"
}; };