Basic overload resolution supported
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {} " +
|
||||
"}"
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user