Basic checks for base initializers in constructors.
Working on Java generics support.
This commit is contained in:
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi;
|
|||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -10,7 +11,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* @author max
|
* @author max
|
||||||
*/
|
*/
|
||||||
public class JetDelegatorToSuperCall extends JetDelegationSpecifier {
|
public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements JetCall {
|
||||||
public JetDelegatorToSuperCall(@NotNull ASTNode node) {
|
public JetDelegatorToSuperCall(@NotNull ASTNode node) {
|
||||||
super(node);
|
super(node);
|
||||||
}
|
}
|
||||||
@@ -20,12 +21,20 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier {
|
|||||||
visitor.visitDelegationToSuperCallSpecifier(this);
|
visitor.visitDelegationToSuperCallSpecifier(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JetArgumentList getArgumentList() {
|
@Nullable
|
||||||
|
public JetArgumentList getValueArgumentList() {
|
||||||
return (JetArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
return (JetArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<JetArgument> getArguments() {
|
@NotNull
|
||||||
JetArgumentList list = getArgumentList();
|
public List<JetArgument> getValueArguments() {
|
||||||
|
JetArgumentList list = getValueArgumentList();
|
||||||
return list != null ? list.getArguments() : Collections.<JetArgument>emptyList();
|
return list != null ? list.getArguments() : Collections.<JetArgument>emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<JetExpression> getFunctionLiteralArguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi;
|
|||||||
|
|
||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetNodeTypes;
|
import org.jetbrains.jet.JetNodeTypes;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -10,7 +11,7 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* @author max
|
* @author max
|
||||||
*/
|
*/
|
||||||
public class JetDelegatorToThisCall extends JetDelegationSpecifier {
|
public class JetDelegatorToThisCall extends JetDelegationSpecifier implements JetCall {
|
||||||
public JetDelegatorToThisCall(@NotNull ASTNode node) {
|
public JetDelegatorToThisCall(@NotNull ASTNode node) {
|
||||||
super(node);
|
super(node);
|
||||||
}
|
}
|
||||||
@@ -20,12 +21,20 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier {
|
|||||||
visitor.visitDelegationToThisCall(this);
|
visitor.visitDelegationToThisCall(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JetArgumentList getArgumentList() {
|
@Nullable
|
||||||
|
public JetArgumentList getValueArgumentList() {
|
||||||
return (JetArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
return (JetArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<JetArgument> getArguments() {
|
@NotNull
|
||||||
JetArgumentList list = getArgumentList();
|
public List<JetArgument> getValueArguments() {
|
||||||
|
JetArgumentList list = getValueArgumentList();
|
||||||
return list != null ? list.getArguments() : Collections.<JetArgument>emptyList();
|
return list != null ? list.getArguments() : Collections.<JetArgument>emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<JetExpression> getFunctionLiteralArguments() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class ClassDescriptorResolver {
|
|||||||
// TODO : assuming that the hierarchy is acyclic
|
// TODO : assuming that the hierarchy is acyclic
|
||||||
Collection<? extends JetType> superclasses = delegationSpecifiers.isEmpty()
|
Collection<? extends JetType> superclasses = delegationSpecifiers.isEmpty()
|
||||||
? Collections.singleton(JetStandardClasses.getAnyType())
|
? Collections.singleton(JetStandardClasses.getAnyType())
|
||||||
: resolveTypes(parameterScope, delegationSpecifiers);
|
: resolveDelegationSpecifiers(parameterScope, delegationSpecifiers);
|
||||||
boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD);
|
boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD);
|
||||||
WritableScope members = resolveMembers(classDescriptor, classElement, typeParameters, scope, parameterScope, superclasses);
|
WritableScope members = resolveMembers(classDescriptor, classElement, typeParameters, scope, parameterScope, superclasses);
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ public class ClassDescriptorResolver {
|
|||||||
// TODO : assuming that the hierarchy is acyclic
|
// TODO : assuming that the hierarchy is acyclic
|
||||||
Collection<? extends JetType> superclasses = delegationSpecifiers.isEmpty()
|
Collection<? extends JetType> superclasses = delegationSpecifiers.isEmpty()
|
||||||
? Collections.singleton(JetStandardClasses.getAnyType())
|
? Collections.singleton(JetStandardClasses.getAnyType())
|
||||||
: resolveTypes(parameterScope, delegationSpecifiers);
|
: resolveDelegationSpecifiers(parameterScope, delegationSpecifiers);
|
||||||
|
|
||||||
// TODO : UGLY HACK
|
// TODO : UGLY HACK
|
||||||
supertypes.addAll(superclasses);
|
supertypes.addAll(superclasses);
|
||||||
@@ -260,7 +260,7 @@ public class ClassDescriptorResolver {
|
|||||||
return typeParameterDescriptor;
|
return typeParameterDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<? extends JetType> resolveTypes(WritableScope extensibleScope, List<JetDelegationSpecifier> delegationSpecifiers) {
|
public Collection<? extends JetType> resolveDelegationSpecifiers(WritableScope extensibleScope, List<JetDelegationSpecifier> delegationSpecifiers) {
|
||||||
if (delegationSpecifiers.isEmpty()) {
|
if (delegationSpecifiers.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
JetExpression bodyExpression = declaration.getBodyExpression();
|
||||||
if (bodyExpression != null) {
|
if (bodyExpression != null) {
|
||||||
computeFlowData(declaration, bodyExpression);
|
computeFlowData(declaration, bodyExpression);
|
||||||
JetFlowInformationProvider flowInformationProvider = computeFlowData(declaration, bodyExpression);
|
JetFlowInformationProvider flowInformationProvider = computeFlowData(declaration, bodyExpression);
|
||||||
JetTypeInferrer typeInferrer = semanticServices.getTypeInferrer(traceForConstructors, flowInformationProvider);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,8 +68,15 @@ public class TypeResolver {
|
|||||||
trace.recordReferenceResolution(referenceExpression, classifierDescriptor);
|
trace.recordReferenceResolution(referenceExpression, classifierDescriptor);
|
||||||
TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor();
|
TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor();
|
||||||
List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments());
|
List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments());
|
||||||
if (arguments.size() != typeConstructor.getParameters().size()) {
|
int expectedArgumentCount = typeConstructor.getParameters().size();
|
||||||
semanticServices.getErrorHandler().genericError(type.getNode(), typeConstructor.getParameters().size() + " type parameters expected"); // TODO : message
|
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 {
|
} else {
|
||||||
result[0] = new JetTypeImpl(
|
result[0] = new JetTypeImpl(
|
||||||
attributes,
|
attributes,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.java;
|
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.openapi.project.Project;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope;
|
||||||
@@ -77,7 +79,7 @@ public class JavaDescriptorResolver {
|
|||||||
classDescriptor.initialize(
|
classDescriptor.initialize(
|
||||||
// TODO
|
// TODO
|
||||||
modifierList == null ? false : modifierList.hasModifierProperty(PsiModifier.FINAL),
|
modifierList == null ? false : modifierList.hasModifierProperty(PsiModifier.FINAL),
|
||||||
Collections.<TypeParameterDescriptor>emptyList(),
|
resolveTypeParameters(psiClass, classDescriptor),
|
||||||
getSupertypes(psiClass),
|
getSupertypes(psiClass),
|
||||||
new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false),
|
new JavaClassMembersScope(classDescriptor, psiClass, semanticServices, false),
|
||||||
constructors
|
constructors
|
||||||
@@ -101,6 +103,41 @@ public class JavaDescriptorResolver {
|
|||||||
return classDescriptor;
|
return classDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<TypeParameterDescriptor> resolveTypeParameters(@NotNull PsiClass psiClass, @NotNull ClassDescriptor classDescriptor) {
|
||||||
|
if (1 < 2) return Collections.emptyList(); // TODO
|
||||||
|
List<TypeParameterDescriptor> result = Lists.newArrayList();
|
||||||
|
PsiTypeParameter[] typeParameters = psiClass.getTypeParameters();
|
||||||
|
for (PsiTypeParameter typeParameter : typeParameters) {
|
||||||
|
PsiClassType[] referencedTypes = typeParameter.getExtendsList().getReferencedTypes();
|
||||||
|
Set<JetType> 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.<Attribute>emptyList(), // TODO
|
||||||
|
Variance.INVARIANT,
|
||||||
|
typeParameter.getName(),
|
||||||
|
upperBounds,
|
||||||
|
boundsAsType
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private Collection<? extends JetType> getSupertypes(PsiClass psiClass) {
|
private Collection<? extends JetType> getSupertypes(PsiClass psiClass) {
|
||||||
List<JetType> result = new ArrayList<JetType>();
|
List<JetType> result = new ArrayList<JetType>();
|
||||||
result.add(JetStandardClasses.getAnyType());
|
result.add(JetStandardClasses.getAnyType());
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.intellij.openapi.project.Project;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||||
import org.jetbrains.jet.lang.types.BindingTrace;
|
import org.jetbrains.jet.lang.types.BindingTrace;
|
||||||
|
import org.jetbrains.jet.lang.types.JetTypeChecker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -12,11 +13,13 @@ public class JavaSemanticServices {
|
|||||||
private final JavaTypeTransformer typeTransformer;
|
private final JavaTypeTransformer typeTransformer;
|
||||||
private final JavaDescriptorResolver descriptorResolver;
|
private final JavaDescriptorResolver descriptorResolver;
|
||||||
private final BindingTrace trace;
|
private final BindingTrace trace;
|
||||||
|
private final JetTypeChecker typeChecker;
|
||||||
|
|
||||||
public JavaSemanticServices(Project project, JetSemanticServices jetSemanticServices, BindingTrace trace) {
|
public JavaSemanticServices(Project project, JetSemanticServices jetSemanticServices, BindingTrace trace) {
|
||||||
this.trace = trace;
|
this.trace = trace;
|
||||||
this.descriptorResolver = new JavaDescriptorResolver(project, this);
|
this.descriptorResolver = new JavaDescriptorResolver(project, this);
|
||||||
this.typeTransformer = new JavaTypeTransformer(jetSemanticServices.getStandardLibrary(), descriptorResolver);
|
this.typeTransformer = new JavaTypeTransformer(jetSemanticServices.getStandardLibrary(), descriptorResolver);
|
||||||
|
this.typeChecker = new JetTypeChecker(jetSemanticServices.getStandardLibrary());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -24,11 +27,18 @@ public class JavaSemanticServices {
|
|||||||
return typeTransformer;
|
return typeTransformer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public JavaDescriptorResolver getDescriptorResolver() {
|
public JavaDescriptorResolver getDescriptorResolver() {
|
||||||
return descriptorResolver;
|
return descriptorResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public BindingTrace getTrace() {
|
public BindingTrace getTrace() {
|
||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetTypeChecker getTypeChecker() {
|
||||||
|
return typeChecker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.java;
|
package org.jetbrains.jet.lang.resolve.java;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
@@ -29,7 +30,8 @@ public class JavaTypeTransformer {
|
|||||||
return javaType.accept(new PsiTypeVisitor<JetType>() {
|
return javaType.accept(new PsiTypeVisitor<JetType>() {
|
||||||
@Override
|
@Override
|
||||||
public JetType visitClassType(PsiClassType classType) {
|
public JetType visitClassType(PsiClassType classType) {
|
||||||
PsiClass psiClass = classType.resolveGenerics().getElement();
|
PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics();
|
||||||
|
PsiClass psiClass = classResolveResult.getElement();
|
||||||
if (psiClass == null) {
|
if (psiClass == null) {
|
||||||
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
return ErrorUtils.createErrorType("Unresolved java class: " + classType.getPresentableText());
|
||||||
}
|
}
|
||||||
@@ -40,8 +42,19 @@ public class JavaTypeTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClassDescriptor descriptor = resolver.resolveClass(psiClass);
|
ClassDescriptor descriptor = resolver.resolveClass(psiClass);
|
||||||
// TODO : arguments & raw types
|
|
||||||
List<TypeProjection> arguments = Collections.<TypeProjection>emptyList(); // TODO
|
List<TypeProjection> arguments = Lists.newArrayList();
|
||||||
|
if (classType.isRaw()) { // TODO
|
||||||
|
// List<TypeParameterDescriptor> 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(
|
return new JetTypeImpl(
|
||||||
Collections.<Attribute>emptyList(),
|
Collections.<Attribute>emptyList(),
|
||||||
descriptor.getTypeConstructor(),
|
descriptor.getTypeConstructor(),
|
||||||
@@ -64,6 +77,12 @@ public class JavaTypeTransformer {
|
|||||||
return TypeUtils.makeNullable(standardLibrary.getArrayType(type));
|
return TypeUtils.makeNullable(standardLibrary.getArrayType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetType visitWildcardType(PsiWildcardType wildcardType) {
|
||||||
|
System.out.println("!!!");
|
||||||
|
return JetStandardClasses.getNullableAnyType(); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetType visitType(PsiType type) {
|
public JetType visitType(PsiType type) {
|
||||||
throw new UnsupportedOperationException("Unsupported type: " + type.getPresentableText()); // TODO
|
throw new UnsupportedOperationException("Unsupported type: " + type.getPresentableText()); // TODO
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
|
|||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
|
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
|
||||||
assert typeArguments.size() == typeConstructor.getParameters().size();
|
assert typeArguments.size() == typeConstructor.getParameters().size() : typeArguments;
|
||||||
if (typeConstructor.getParameters().isEmpty()) {
|
if (typeConstructor.getParameters().isEmpty()) {
|
||||||
return memberDeclarations;
|
return memberDeclarations;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -379,6 +379,171 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JetType resolveOverloads(JetScope scope, JetCallExpression expression, OverloadDomain overloadDomain) {
|
||||||
|
List<JetTypeProjection> typeArguments = expression.getTypeArguments();
|
||||||
|
List<JetArgument> valueArguments = expression.getValueArguments();
|
||||||
|
List<JetExpression> functionLiteralArguments = expression.getFunctionLiteralArguments();
|
||||||
|
return resolveOverloads(scope, overloadDomain, typeArguments, valueArguments, functionLiteralArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private JetType resolveOverloads(
|
||||||
|
@NotNull JetScope scope,
|
||||||
|
@NotNull OverloadDomain overloadDomain,
|
||||||
|
@NotNull List<JetTypeProjection> typeArguments,
|
||||||
|
@NotNull List<JetArgument> valueArguments,
|
||||||
|
@NotNull List<JetExpression> 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<JetType> types = new ArrayList<JetType>();
|
||||||
|
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<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
|
||||||
|
for (JetArgument argument : valueArguments) {
|
||||||
|
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||||
|
if (argumentExpression != null) {
|
||||||
|
positionedValueArguments.add(argumentExpression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
positionedValueArguments.addAll(functionLiteralArguments);
|
||||||
|
|
||||||
|
List<JetType> valueArgumentTypes = new ArrayList<JetType>();
|
||||||
|
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<in T>(...)' this does not make much sense, and an instance
|
||||||
|
// of 'Array<T>' 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<in T> = new Array<T>(...)
|
||||||
|
// 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<TypeProjection> typeArguments = receiverType.getArguments();
|
||||||
|
|
||||||
|
List<TypeProjection> projectionsStripped = new ArrayList<TypeProjection>();
|
||||||
|
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.<JetTypeProjection>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 class TypeInferrerVisitor extends JetVisitor {
|
||||||
private final JetScope scope;
|
private final JetScope scope;
|
||||||
private final boolean preferBlock;
|
private final boolean preferBlock;
|
||||||
@@ -968,89 +1133,7 @@ public class JetTypeInferrer {
|
|||||||
// TODO : type argument inference
|
// TODO : type argument inference
|
||||||
JetTypeReference typeReference = expression.getTypeReference();
|
JetTypeReference typeReference = expression.getTypeReference();
|
||||||
if (typeReference != null) {
|
if (typeReference != null) {
|
||||||
JetTypeElement typeElement = typeReference.getTypeElement();
|
result = getTypeForConstructorCall(scope, typeReference, expression);
|
||||||
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<in T>(...)' this does not make much sense, and an instance
|
|
||||||
// of 'Array<T>' 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<in T> = new Array<T>(...)
|
|
||||||
// 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<TypeProjection> typeArguments = receiverType.getArguments();
|
|
||||||
|
|
||||||
List<TypeProjection> projectionsStripped = new ArrayList<TypeProjection>();
|
|
||||||
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.<JetTypeProjection>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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1108,80 +1191,6 @@ public class JetTypeInferrer {
|
|||||||
result = resolveOverloads(scope, expression, overloadDomain);
|
result = resolveOverloads(scope, expression, overloadDomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private JetType resolveOverloads(JetScope scope, JetCallExpression expression, OverloadDomain overloadDomain) {
|
|
||||||
List<JetTypeProjection> typeArguments = expression.getTypeArguments();
|
|
||||||
List<JetArgument> valueArguments = expression.getValueArguments();
|
|
||||||
List<JetExpression> functionLiteralArguments = expression.getFunctionLiteralArguments();
|
|
||||||
return resolveOverloads(scope, overloadDomain, typeArguments, valueArguments, functionLiteralArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private JetType resolveOverloads(
|
|
||||||
@NotNull JetScope scope,
|
|
||||||
@NotNull OverloadDomain overloadDomain,
|
|
||||||
@NotNull List<JetTypeProjection> typeArguments,
|
|
||||||
@NotNull List<JetArgument> valueArguments,
|
|
||||||
@NotNull List<JetExpression> 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<JetType> types = new ArrayList<JetType>();
|
|
||||||
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<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
|
|
||||||
for (JetArgument argument : valueArguments) {
|
|
||||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
|
||||||
if (argumentExpression != null) {
|
|
||||||
positionedValueArguments.add(argumentExpression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
positionedValueArguments.addAll(functionLiteralArguments);
|
|
||||||
|
|
||||||
List<JetType> valueArgumentTypes = new ArrayList<JetType>();
|
|
||||||
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
|
@Override
|
||||||
public void visitIsExpression(JetIsExpression expression) {
|
public void visitIsExpression(JetIsExpression expression) {
|
||||||
// TODO : patterns and everything
|
// TODO : patterns and everything
|
||||||
|
|||||||
@@ -27,6 +27,13 @@ public class TypeUtils {
|
|||||||
return new JetTypeImpl(type.getAttributes(), type.getConstructor(), nullable, type.getArguments(), type.getMemberScope());
|
return new JetTypeImpl(type.getAttributes(), type.getConstructor(), nullable, type.getArguments(), type.getMemberScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static JetType safeIntersect(JetTypeChecker typeChecker, Set<JetType> types) {
|
||||||
|
JetType intersection = intersect(typeChecker, types);
|
||||||
|
if (intersection == null) return ErrorUtils.createErrorType("No intersection for " + types); // TODO : message
|
||||||
|
return intersection;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static JetType intersect(JetTypeChecker typeChecker, Set<JetType> types) {
|
public static JetType intersect(JetTypeChecker typeChecker, Set<JetType> types) {
|
||||||
assert !types.isEmpty();
|
assert !types.isEmpty();
|
||||||
@@ -212,12 +219,11 @@ public class TypeUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Set<JetType> getAllSupertypes(@NotNull JetType type) {
|
public static Set<JetType> getAllSupertypes(@NotNull JetType type) {
|
||||||
Set<JetType> result = Sets.newLinkedHashSet();
|
Set<JetType> result = Sets.newLinkedHashSet();
|
||||||
collectAllSupertypes(type, result);
|
collectAllSupertypes(type, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user