diff --git a/idea/src/org/jetbrains/jet/lang/ErrorHandler.java b/idea/src/org/jetbrains/jet/lang/ErrorHandler.java index f493e04c086..f3c6aec0bf6 100644 --- a/idea/src/org/jetbrains/jet/lang/ErrorHandler.java +++ b/idea/src/org/jetbrains/jet/lang/ErrorHandler.java @@ -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) { + } } diff --git a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java index 1986f329b43..b185e10b3c2 100644 --- a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -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; + } } diff --git a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java index 902f76213da..4df270d6376 100644 --- a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java @@ -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 diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index c706374c7a4..4e7a55bdfa5 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -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 maximallySpecific = new ArrayList(); + 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 fParams = f.getUnsubstitutedValueParameters(); + List 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; + } + } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 6138aadb5ff..401b2de46f8 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -36,76 +36,78 @@ public class TypeResolver { private Type resolveTypeElement(final JetScope scope, final List 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 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 arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments()); result[0] = new TypeImpl( attributes, - typeParameterDescriptor.getTypeConstructor(), - nullable || hasNullableBound(typeParameterDescriptor), - Collections.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.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 parameterTypes = new ArrayList(); - 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 parameterTypes = new ArrayList(); + 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 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 case diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java index 1657909d03e..ba1bd87d6ad 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java @@ -61,6 +61,6 @@ public class WritableFunctionGroup implements FunctionGroup { @Override public boolean isEmpty() { - return functionDescriptors.isEmpty(); + return functionDescriptors == null || functionDescriptors.isEmpty(); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java index 77accc53570..a72f56e645b 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableScope.java @@ -160,6 +160,7 @@ public class WritableScope extends JetScopeAdapter { public void addClassAlias(String name, ClassDescriptor classDescriptor) { Map classDescriptors = getClassDescriptors(); if (classDescriptors.put(name, classDescriptor) != null) { + throw new UnsupportedOperationException("Class redeclared: " + classDescriptor.getName()); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java index ee1678ac791..7f4f9854ff4 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java @@ -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; } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index 36ff5718d28..b260eeab7fe 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -59,13 +59,29 @@ public class JavaDescriptorResolver { modifierList == null ? false : modifierList.hasModifierProperty(PsiModifier.FINAL), name, Collections.emptyList(), - Collections.emptyList(), + getSupertypes(psiClass), new JavaClassMembersScope(psiClass, semanticServices, false) ); semanticServices.getTrace().recordDeclarationResolution(psiClass, classDescriptor); return classDescriptor; } + private Collection getSupertypes(PsiClass psiClass) { + List result = new ArrayList(); + result.add(JetStandardClasses.getAnyType()); + transformSupertypeList(result, psiClass.getExtendsListTypes()); + transformSupertypeList(result, psiClass.getImplementsListTypes()); + return result; + } + + private void transformSupertypeList(List 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) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java index f477239417e..99ce320f463 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java @@ -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() { + return javaType.accept(new PsiTypeVisitor() { @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 arguments = Collections.emptyList(); // TODO + return new TypeImpl( + Collections.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 getPrimitiveTypesMap() { diff --git a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java index 97c207623e9..974d254bcd7 100644 --- a/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/DeclarationDescriptorImpl.java @@ -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 visitor) { accept(visitor, null); } + + @Override + public String toString() { + return DescriptorUtil.renderPresentableText(this) + "[" + getClass().getCanonicalName()+ "]"; + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 3ed0f3a915b..fab2ac4b3fe 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -10,9 +10,57 @@ import java.util.*; */ public class JetTypeChecker { - public static final JetTypeChecker INSTANCE = new JetTypeChecker(); + private final Map> conversionMap = new HashMap>(); + private final JetStandardLibrary standardLibrary; - private JetTypeChecker() {} + public JetTypeChecker(JetStandardLibrary standardLibrary) { + this.standardLibrary = standardLibrary; + } + + private Map> 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(Arrays.asList(constructors))); + } public Type commonSupertype(Collection types) { Collection typeSet = new HashSet(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 convertibleTo = getConversionMap().get(actualConstructor); + if (convertibleTo != null) { + return convertibleTo.contains(constructor); + } + } + return false; } public boolean isSubtypeOf(Type subtype, Type supertype) { diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 8424963a96c..2815e4223ff 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -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 expressions = new ArrayList(); 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.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; } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java index b8c5fd13e36..d18097975c3 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -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 types) { + public static Type intersect(JetTypeChecker typeChecker, Set types) { assert !types.isEmpty(); if (types.size() == 1) { @@ -31,9 +38,9 @@ public class TypeUtils { for (Iterator 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; } diff --git a/idea/testData/resolve/ResolveToJava.jet b/idea/testData/resolve/ResolveToJava.jet index 5fd30ba8b86..6cf3bc5e0f3 100644 --- a/idea/testData/resolve/ResolveToJava.jet +++ b/idea/testData/resolve/ResolveToJava.jet @@ -33,4 +33,17 @@ class B : `java::java.lang.Object`Object { fun barrr() : `std::Int`Int { `foo`foo(new `A`A()) } -} \ No newline at end of file +} + +~c~fun c(~x~x : `java::java.lang.Number`Number) { + `x`x.`java::java.lang.Number.intValue()`intValue() +} + +fun 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?) + 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) +} diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index 13e47b16170..f6169707e53 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -36,18 +36,25 @@ public class JetResolveTest extends ExtensibleResolveTestCase { nameToDescriptor.put("std::Array.set(Int, Int)", descriptorForSet.getOriginal()); Map nameToDeclaration = new HashMap(); - 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); } diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index f5884301402..1dab2c374a8 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -342,7 +342,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { assertType("new Functions().f()", "Unit"); assertType("new Functions().f(1)", "Int"); assertType("new Functions().f(1d)", (String) null); - assertType("new Functions().f(())", "Double"); + assertType("new Functions().f((1, 1))", "Double"); assertType("new Functions().f(1d)", "Any"); assertType("new Functions().f(\"\")", "Byte"); assertType("new Functions().f(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(a : E) : T {} " + "}" };