From eb7ac0cf916dba33bd7e7efde0ab4dd3a7030331 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 21 Apr 2011 17:45:46 +0400 Subject: [PATCH] Basic checks for base initializers in constructors. Working on Java generics support. --- .../jet/lang/psi/JetDelegatorToSuperCall.java | 17 +- .../jet/lang/psi/JetDelegatorToThisCall.java | 17 +- .../lang/resolve/ClassDescriptorResolver.java | 6 +- .../jet/lang/resolve/TopDownAnalyzer.java | 49 ++- .../jet/lang/resolve/TypeResolver.java | 11 +- .../resolve/java/JavaDescriptorResolver.java | 39 ++- .../resolve/java/JavaSemanticServices.java | 10 + .../resolve/java/JavaTypeTransformer.java | 25 +- .../jet/lang/types/ClassDescriptorImpl.java | 2 +- .../jet/lang/types/JetTypeInferrer.java | 323 +++++++++--------- .../jetbrains/jet/lang/types/TypeUtils.java | 10 +- 11 files changed, 326 insertions(+), 183 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java index 436984b9478..97a9c3f4725 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import java.util.Collections; @@ -10,7 +11,7 @@ import java.util.List; /** * @author max */ -public class JetDelegatorToSuperCall extends JetDelegationSpecifier { +public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements JetCall { public JetDelegatorToSuperCall(@NotNull ASTNode node) { super(node); } @@ -20,12 +21,20 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier { visitor.visitDelegationToSuperCallSpecifier(this); } - public JetArgumentList getArgumentList() { + @Nullable + public JetArgumentList getValueArgumentList() { return (JetArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST); } - public List getArguments() { - JetArgumentList list = getArgumentList(); + @NotNull + public List getValueArguments() { + JetArgumentList list = getValueArgumentList(); return list != null ? list.getArguments() : Collections.emptyList(); } + + @NotNull + @Override + public List getFunctionLiteralArguments() { + return Collections.emptyList(); + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java index ed462315bf8..658799c7611 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import java.util.Collections; @@ -10,7 +11,7 @@ import java.util.List; /** * @author max */ -public class JetDelegatorToThisCall extends JetDelegationSpecifier { +public class JetDelegatorToThisCall extends JetDelegationSpecifier implements JetCall { public JetDelegatorToThisCall(@NotNull ASTNode node) { super(node); } @@ -20,12 +21,20 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier { visitor.visitDelegationToThisCall(this); } - public JetArgumentList getArgumentList() { + @Nullable + public JetArgumentList getValueArgumentList() { return (JetArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST); } - public List getArguments() { - JetArgumentList list = getArgumentList(); + @NotNull + public List getValueArguments() { + JetArgumentList list = getValueArgumentList(); return list != null ? list.getArguments() : Collections.emptyList(); } + + @NotNull + @Override + public List getFunctionLiteralArguments() { + return Collections.emptyList(); + } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index d06e4c556b6..18377fc1a9f 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -50,7 +50,7 @@ public class ClassDescriptorResolver { // TODO : assuming that the hierarchy is acyclic Collection superclasses = delegationSpecifiers.isEmpty() ? Collections.singleton(JetStandardClasses.getAnyType()) - : resolveTypes(parameterScope, delegationSpecifiers); + : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers); boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD); WritableScope members = resolveMembers(classDescriptor, classElement, typeParameters, scope, parameterScope, superclasses); @@ -98,7 +98,7 @@ public class ClassDescriptorResolver { // TODO : assuming that the hierarchy is acyclic Collection superclasses = delegationSpecifiers.isEmpty() ? Collections.singleton(JetStandardClasses.getAnyType()) - : resolveTypes(parameterScope, delegationSpecifiers); + : resolveDelegationSpecifiers(parameterScope, delegationSpecifiers); // TODO : UGLY HACK supertypes.addAll(superclasses); @@ -260,7 +260,7 @@ public class ClassDescriptorResolver { return typeParameterDescriptor; } - public Collection resolveTypes(WritableScope extensibleScope, List delegationSpecifiers) { + public Collection resolveDelegationSpecifiers(WritableScope extensibleScope, List delegationSpecifiers) { if (delegationSpecifiers.isEmpty()) { return Collections.emptyList(); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 78ac6afec08..5d727b16dba 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -296,18 +296,55 @@ public class TopDownAnalyzer { } } - private void resolveConstructorBody(JetConstructor declaration, FunctionDescriptor descriptor, WritableScope declaringScope) { + private void resolveConstructorBody(JetConstructor declaration, FunctionDescriptor descriptor, final WritableScope declaringScope) { + WritableScope constructorScope = semanticServices.createWritableScope(declaringScope, declaringScope.getContainingDeclaration()); + for (PropertyDescriptor propertyDescriptor : declaringScopesToProperties.get(descriptor.getContainingDeclaration())) { + constructorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); + } + final JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(constructorScope, descriptor, semanticServices); + final JetTypeInferrer typeInferrerForInitializers = semanticServices.getTypeInferrer(traceForConstructors, JetFlowInformationProvider.NONE); + for (JetDelegationSpecifier initializer : declaration.getInitializers()) { + // TODO : check that the type being referenced is actually a supertype + initializer.accept(new JetVisitor() { + @Override + public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) { + JetTypeReference typeReference = call.getTypeReference(); + if (typeReference != null) { + typeInferrerForInitializers.getTypeForConstructorCall(functionInnerScope, typeReference, call); + } + } + + @Override + public void visitDelegationToThisCall(JetDelegatorToThisCall call) { + JetTypeReference typeReference = call.getTypeReference(); // TODO : use explicit type here + if (typeReference != null) { + typeInferrerForInitializers.getTypeForConstructorCall(functionInnerScope, typeReference, call); + } + } + + @Override + public void visitDelegationByExpressionSpecifier(JetDelegatorByExpressionSpecifier specifier) { + semanticServices.getErrorHandler().genericError(specifier.getNode(), "'by'-clause is only supported for primary constructors"); + } + + @Override + public void visitDelegationToSuperClassSpecifier(JetDelegatorToSuperClass specifier) { + semanticServices.getErrorHandler().genericError(specifier.getNode(), "Constructor parameters required"); + } + + @Override + public void visitDelegationSpecifier(JetDelegationSpecifier specifier) { + throw new IllegalStateException(); + } + }); + } JetExpression bodyExpression = declaration.getBodyExpression(); if (bodyExpression != null) { computeFlowData(declaration, bodyExpression); JetFlowInformationProvider flowInformationProvider = computeFlowData(declaration, bodyExpression); JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider); - WritableScope constructorScope = semanticServices.createWritableScope(declaringScope, declaringScope.getContainingDeclaration()); - for (PropertyDescriptor propertyDescriptor : declaringScopesToProperties.get(descriptor.getContainingDeclaration())) { - constructorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor); - } - typeInferrer.getType(FunctionDescriptorUtil.getFunctionInnerScope(constructorScope, descriptor, semanticServices), bodyExpression, true); + typeInferrer.getType(functionInnerScope, bodyExpression, true); } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index e92fe4f22c1..d0f4073fcb1 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -68,8 +68,15 @@ public class TypeResolver { trace.recordReferenceResolution(referenceExpression, classifierDescriptor); TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor(); List arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments()); - if (arguments.size() != typeConstructor.getParameters().size()) { - semanticServices.getErrorHandler().genericError(type.getNode(), typeConstructor.getParameters().size() + " type parameters expected"); // TODO : message + int expectedArgumentCount = typeConstructor.getParameters().size(); + int actualArgumentCount = arguments.size(); + if (actualArgumentCount != expectedArgumentCount) { + String errorMessage = (expectedArgumentCount == 0 ? "No" : expectedArgumentCount) + " type arguments expected"; + if (actualArgumentCount == 0) { + semanticServices.getErrorHandler().genericError(type.getNode(), errorMessage); + } else if (expectedArgumentCount == 0) { + semanticServices.getErrorHandler().genericError(type.getTypeArgumentList().getNode(), errorMessage); + } } else { result[0] = new JetTypeImpl( attributes, 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 17b484ae4a9..22b31f78a42 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -1,5 +1,7 @@ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -77,7 +79,7 @@ public class JavaDescriptorResolver { classDescriptor.initialize( // TODO modifierList == null ? false : modifierList.hasModifierProperty(PsiModifier.FINAL), - Collections.emptyList(), + resolveTypeParameters(psiClass, classDescriptor), getSupertypes(psiClass), new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false), constructors @@ -101,6 +103,41 @@ public class JavaDescriptorResolver { return classDescriptor; } + private List resolveTypeParameters(@NotNull PsiClass psiClass, @NotNull ClassDescriptor classDescriptor) { + if (1 < 2) return Collections.emptyList(); // TODO + List result = Lists.newArrayList(); + PsiTypeParameter[] typeParameters = psiClass.getTypeParameters(); + for (PsiTypeParameter typeParameter : typeParameters) { + PsiClassType[] referencedTypes = typeParameter.getExtendsList().getReferencedTypes(); + Set upperBounds; + JetType boundsAsType; + if (referencedTypes.length == 0){ + boundsAsType = JetStandardClasses.getNullableAnyType(); + upperBounds = Collections.singleton(boundsAsType); + } + else if (referencedTypes.length == 1) { + boundsAsType = semanticServices.getTypeTransformer().transform(referencedTypes[0]); + upperBounds = Collections.singleton(boundsAsType); + } + else { + upperBounds = Sets.newLinkedHashSet(); + for (PsiClassType referencedType : referencedTypes) { + upperBounds.add(semanticServices.getTypeTransformer().transform(referencedType)); + } + boundsAsType = TypeUtils.safeIntersect(semanticServices.getTypeChecker(), upperBounds); + } + result.add(new TypeParameterDescriptor( + classDescriptor, + Collections.emptyList(), // TODO + Variance.INVARIANT, + typeParameter.getName(), + upperBounds, + boundsAsType + )); + } + return result; + } + private Collection getSupertypes(PsiClass psiClass) { List result = new ArrayList(); result.add(JetStandardClasses.getAnyType()); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaSemanticServices.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaSemanticServices.java index 1ac157e8777..a3d6dcd513b 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaSemanticServices.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaSemanticServices.java @@ -4,6 +4,7 @@ import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.types.BindingTrace; +import org.jetbrains.jet.lang.types.JetTypeChecker; /** * @author abreslav @@ -12,11 +13,13 @@ public class JavaSemanticServices { private final JavaTypeTransformer typeTransformer; private final JavaDescriptorResolver descriptorResolver; private final BindingTrace trace; + private final JetTypeChecker typeChecker; public JavaSemanticServices(Project project, JetSemanticServices jetSemanticServices, BindingTrace trace) { this.trace = trace; this.descriptorResolver = new JavaDescriptorResolver(project, this); this.typeTransformer = new JavaTypeTransformer(jetSemanticServices.getStandardLibrary(), descriptorResolver); + this.typeChecker = new JetTypeChecker(jetSemanticServices.getStandardLibrary()); } @NotNull @@ -24,11 +27,18 @@ public class JavaSemanticServices { return typeTransformer; } + @NotNull public JavaDescriptorResolver getDescriptorResolver() { return descriptorResolver; } + @NotNull public BindingTrace getTrace() { return trace; } + + @NotNull + public JetTypeChecker getTypeChecker() { + return typeChecker; + } } 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 395f25e0912..2f9ad2d1abc 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.collect.Lists; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.types.*; @@ -29,7 +30,8 @@ public class JavaTypeTransformer { return javaType.accept(new PsiTypeVisitor() { @Override public JetType visitClassType(PsiClassType classType) { - PsiClass psiClass = classType.resolveGenerics().getElement(); + PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics(); + PsiClass psiClass = classResolveResult.getElement(); if (psiClass == null) { return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText()); } @@ -40,8 +42,19 @@ public class JavaTypeTransformer { } ClassDescriptor descriptor = resolver.resolveClass(psiClass); - // TODO : arguments & raw types - List arguments = Collections.emptyList(); // TODO + + List arguments = Lists.newArrayList(); + if (classType.isRaw()) { // TODO +// List parameters = descriptor.getTypeConstructor().getParameters(); +// for (TypeParameterDescriptor parameter : parameters) { +// arguments.add(TypeUtils.makeStarProjection(parameter)); +// } + } else { // TODO +// PsiType[] psiArguments = classType.getParameters(); +// for (PsiType psiArgument : psiArguments) { +// arguments.add(new TypeProjection(transform(psiArgument))); +// } + } return new JetTypeImpl( Collections.emptyList(), descriptor.getTypeConstructor(), @@ -64,6 +77,12 @@ public class JavaTypeTransformer { return TypeUtils.makeNullable(standardLibrary.getArrayType(type)); } + @Override + public JetType visitWildcardType(PsiWildcardType wildcardType) { + System.out.println("!!!"); + return JetStandardClasses.getNullableAnyType(); // TODO + } + @Override public JetType visitType(PsiType type) { throw new UnsupportedOperationException("Unsupported type: " + type.getPresentableText()); // TODO diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java index 511d37a158c..47e28377b3a 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java @@ -44,7 +44,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl @Override @NotNull public JetScope getMemberScope(List typeArguments) { - assert typeArguments.size() == typeConstructor.getParameters().size(); + assert typeArguments.size() == typeConstructor.getParameters().size() : typeArguments; if (typeConstructor.getParameters().isEmpty()) { return memberDeclarations; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index a9760ad3436..f888c5c781b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -379,6 +379,171 @@ public class JetTypeInferrer { } } + @Nullable + private JetType resolveOverloads(JetScope scope, JetCallExpression expression, OverloadDomain overloadDomain) { + List typeArguments = expression.getTypeArguments(); + List valueArguments = expression.getValueArguments(); + List functionLiteralArguments = expression.getFunctionLiteralArguments(); + return resolveOverloads(scope, overloadDomain, typeArguments, valueArguments, functionLiteralArguments); + } + + @Nullable + private JetType resolveOverloads( + @NotNull JetScope scope, + @NotNull OverloadDomain overloadDomain, + @NotNull List typeArguments, + @NotNull List valueArguments, + @NotNull List functionLiteralArguments) { + // 1) ends with a name -> (scope, name) to look up + // 2) ends with something else -> just check types + + for (JetTypeProjection typeArgument : typeArguments) { + if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { + semanticServices.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning + } + } + + boolean someNamed = false; + for (JetArgument argument : valueArguments) { + if (argument.isNamed()) { + someNamed = true; + break; + } + } + +// JetExpression functionLiteralArgument = functionLiteralArguments.isEmpty() ? null : functionLiteralArguments.get(0); + // TODO : must be a check + assert functionLiteralArguments.size() <= 1; + + if (someNamed) { + // TODO : check that all are named + throw new UnsupportedOperationException(); // TODO + +// result = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArguments, functionLiteralArgument); + } else { + List types = new ArrayList(); + for (JetTypeProjection projection : typeArguments) { + // TODO : check that there's no projection + JetTypeReference typeReference = projection.getTypeReference(); + if (typeReference != null) { + types.add(typeResolver.resolveType(scope, typeReference)); + } + } + + List positionedValueArguments = new ArrayList(); + for (JetArgument argument : valueArguments) { + JetExpression argumentExpression = argument.getArgumentExpression(); + if (argumentExpression != null) { + positionedValueArguments.add(argumentExpression); + } + } + + positionedValueArguments.addAll(functionLiteralArguments); + + List valueArgumentTypes = new ArrayList(); + for (JetExpression valueArgument : positionedValueArguments) { + valueArgumentTypes.add(safeGetType(scope, valueArgument, false)); + } + + OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes); + if (resolutionResult.isSuccess()) { + return resolutionResult.getFunctionDescriptor().getUnsubstitutedReturnType(); + } + } + return null; + } + + @Nullable + public JetType getTypeForConstructorCall(JetScope scope, @NotNull JetTypeReference typeReference, @NotNull JetCall call) { + JetTypeElement typeElement = typeReference.getTypeElement(); + if (typeElement instanceof JetUserType) { + JetUserType userType = (JetUserType) typeElement; + // TODO : to infer constructor parameters, one will need to + // 1) resolve a _class_ from the typeReference + // 2) rely on the overload domain of constructors of this class to infer type arguments + // For now we assume that the type arguments are provided, and thus the typeReference can be + // resolved into a valid type + JetType receiverType = typeResolver.resolveType(scope, typeReference); + DeclarationDescriptor declarationDescriptor = receiverType.getConstructor().getDeclarationDescriptor(); + if (declarationDescriptor instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; + + for (JetTypeProjection typeProjection : userType.getTypeArguments()) { + switch (typeProjection.getProjectionKind()) { + case IN: + case OUT: + case STAR: + // TODO : Bug in the editor + semanticServices.getErrorHandler().genericError(typeProjection.getProjectionNode(), "Projections are not allowed in constructor type arguments"); + break; + case NONE: + break; + } + } + + JetSimpleNameExpression referenceExpression = userType.getReferenceExpression(); + if (referenceExpression != null) { + // When one writes 'new Array(...)' this does not make much sense, and an instance + // of 'Array' must be created anyway. + // Thus, we should either prohibit projections in type arguments in such contexts, + // or treat them as an automatic upcast to the desired type, i.e. for the user not + // to be forced to write + // val a : Array = new Array(...) + // NOTE: Array may be a bad example here, some classes may have substantial functionality + // not involving their type parameters + // + // The code below upcasts the type automatically + + List typeArguments = receiverType.getArguments(); + + List projectionsStripped = new ArrayList(); + for (TypeProjection typeArgument : typeArguments) { + if (typeArgument.getProjectionKind() != Variance.INVARIANT) { + projectionsStripped.add(new TypeProjection(typeArgument.getType())); + } + else + projectionsStripped.add(typeArgument); + } + + FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped); + OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors); + JetType constructorReturnedType = resolveOverloads( + scope, + wrapForTracing(constructorsOverloadDomain, referenceExpression, call.getValueArgumentList(), false), + Collections.emptyList(), + call.getValueArguments(), + call.getFunctionLiteralArguments()); + if (constructorReturnedType == null && !ErrorUtils.isErrorType(receiverType)) { + trace.recordReferenceResolution(referenceExpression, receiverType.getConstructor().getDeclarationDescriptor()); + // TODO : more helpful message + JetArgumentList argumentList = call.getValueArgumentList(); + if (argumentList != null) { + semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Cannot find an overload for these arguments"); + } + constructorReturnedType = receiverType; + } + // If no upcast needed: + return constructorReturnedType; + + // Automatic upcast: +// result = receiverType; + } + } + else { + semanticServices.getErrorHandler().genericError(((JetElement) call).getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : review the message + } + } + else { + if (typeElement != null) { + semanticServices.getErrorHandler().genericError(typeElement.getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : Better message + } + } + return null; + } + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private class TypeInferrerVisitor extends JetVisitor { private final JetScope scope; private final boolean preferBlock; @@ -968,89 +1133,7 @@ public class JetTypeInferrer { // TODO : type argument inference JetTypeReference typeReference = expression.getTypeReference(); if (typeReference != null) { - JetTypeElement typeElement = typeReference.getTypeElement(); - if (typeElement instanceof JetUserType) { - JetUserType userType = (JetUserType) typeElement; - // TODO : to infer constructor parameters, one will need to - // 1) resolve a _class_ from the typeReference - // 2) rely on the overload domain of constructors of this class to infer type arguments - // For now we assume that the type arguments are provided, and thus the typeReference can be - // resolved into a valid type - JetType receiverType = typeResolver.resolveType(scope, typeReference); - DeclarationDescriptor declarationDescriptor = receiverType.getConstructor().getDeclarationDescriptor(); - if (declarationDescriptor instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; - - for (JetTypeProjection typeProjection : userType.getTypeArguments()) { - switch (typeProjection.getProjectionKind()) { - case IN: - case OUT: - case STAR: - // TODO : Bug in the editor - semanticServices.getErrorHandler().genericError(typeProjection.getProjectionNode(), "Projections are not allowed in constructor type arguments"); - break; - case NONE: - break; - } - } - - JetSimpleNameExpression referenceExpression = userType.getReferenceExpression(); - if (referenceExpression != null) { - // When one writes 'new Array(...)' this does not make much sense, and an instance - // of 'Array' must be created anyway. - // Thus, we should either prohibit projections in type arguments in such contexts, - // or treat them as an automatic upcast to the desired type, i.e. for the user not - // to be forced to write - // val a : Array = new Array(...) - // NOTE: Array may be a bad example here, some classes may have substantial functionality - // not involving their type parameters - // - // The code below upcasts the type automatically - - List typeArguments = receiverType.getArguments(); - - List projectionsStripped = new ArrayList(); - for (TypeProjection typeArgument : typeArguments) { - if (typeArgument.getProjectionKind() != Variance.INVARIANT) { - projectionsStripped.add(new TypeProjection(typeArgument.getType())); - } - else - projectionsStripped.add(typeArgument); - } - - FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped); - OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors); - JetType constructorReturnedType = resolveOverloads( - scope, - wrapForTracing(constructorsOverloadDomain, referenceExpression, expression.getValueArgumentList(), false), - Collections.emptyList(), - expression.getValueArguments(), - expression.getFunctionLiteralArguments()); - if (constructorReturnedType == null && !ErrorUtils.isErrorType(receiverType)) { - trace.recordReferenceResolution(referenceExpression, receiverType.getConstructor().getDeclarationDescriptor()); - // TODO : more helpful message - JetArgumentList argumentList = expression.getValueArgumentList(); - if (argumentList != null) { - semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Cannot find an overload for these arguments"); - } - constructorReturnedType = receiverType; - } - // If no upcast needed: - result = constructorReturnedType; - - // Automatic upcast: -// result = receiverType; - } - } - else { - semanticServices.getErrorHandler().genericError(expression.getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : review the message - } - } - else { - if (typeElement != null) { - semanticServices.getErrorHandler().genericError(typeElement.getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : Better message - } - } + result = getTypeForConstructorCall(scope, typeReference, expression); } } @@ -1108,80 +1191,6 @@ public class JetTypeInferrer { result = resolveOverloads(scope, expression, overloadDomain); } - @Nullable - private JetType resolveOverloads(JetScope scope, JetCallExpression expression, OverloadDomain overloadDomain) { - List typeArguments = expression.getTypeArguments(); - List valueArguments = expression.getValueArguments(); - List functionLiteralArguments = expression.getFunctionLiteralArguments(); - return resolveOverloads(scope, overloadDomain, typeArguments, valueArguments, functionLiteralArguments); - } - - @Nullable - private JetType resolveOverloads( - @NotNull JetScope scope, - @NotNull OverloadDomain overloadDomain, - @NotNull List typeArguments, - @NotNull List valueArguments, - @NotNull List functionLiteralArguments) { - // 1) ends with a name -> (scope, name) to look up - // 2) ends with something else -> just check types - - for (JetTypeProjection typeArgument : typeArguments) { - if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { - semanticServices.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning - } - } - - boolean someNamed = false; - for (JetArgument argument : valueArguments) { - if (argument.isNamed()) { - someNamed = true; - break; - } - } - -// JetExpression functionLiteralArgument = functionLiteralArguments.isEmpty() ? null : functionLiteralArguments.get(0); - // TODO : must be a check - assert functionLiteralArguments.size() <= 1; - - if (someNamed) { - // TODO : check that all are named - throw new UnsupportedOperationException(); // TODO - -// result = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArguments, functionLiteralArgument); - } else { - List types = new ArrayList(); - for (JetTypeProjection projection : typeArguments) { - // TODO : check that there's no projection - JetTypeReference typeReference = projection.getTypeReference(); - if (typeReference != null) { - types.add(typeResolver.resolveType(scope, typeReference)); - } - } - - List positionedValueArguments = new ArrayList(); - for (JetArgument argument : valueArguments) { - JetExpression argumentExpression = argument.getArgumentExpression(); - if (argumentExpression != null) { - positionedValueArguments.add(argumentExpression); - } - } - - positionedValueArguments.addAll(functionLiteralArguments); - - List valueArgumentTypes = new ArrayList(); - for (JetExpression valueArgument : positionedValueArguments) { - valueArgumentTypes.add(safeGetType(scope, valueArgument, false)); - } - - OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes); - if (resolutionResult.isSuccess()) { - return resolutionResult.getFunctionDescriptor().getUnsubstitutedReturnType(); - } - } - return null; - } - @Override public void visitIsExpression(JetIsExpression expression) { // TODO : patterns and everything diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java index 5066648eea5..8a021b68000 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -27,6 +27,13 @@ public class TypeUtils { return new JetTypeImpl(type.getAttributes(), type.getConstructor(), nullable, type.getArguments(), type.getMemberScope()); } + @NotNull + public static JetType safeIntersect(JetTypeChecker typeChecker, Set types) { + JetType intersection = intersect(typeChecker, types); + if (intersection == null) return ErrorUtils.createErrorType("No intersection for " + types); // TODO : message + return intersection; + } + @Nullable public static JetType intersect(JetTypeChecker typeChecker, Set types) { assert !types.isEmpty(); @@ -212,12 +219,11 @@ public class TypeUtils { } } + @NotNull public static Set getAllSupertypes(@NotNull JetType type) { Set result = Sets.newLinkedHashSet(); collectAllSupertypes(type, result); return result; } - - }