diff --git a/grammar/src/class_members.grm b/grammar/src/class_members.grm index ac73ca56d1b..addd0c4eb65 100644 --- a/grammar/src/class_members.grm +++ b/grammar/src/class_members.grm @@ -119,7 +119,7 @@ parameter ; object - : "object" SimpleName ":" delegationSpecifier{","}? classBody? // Class body can be optional: this is a declaration + : "object" SimpleName (":" delegationSpecifier{","})? classBody? // Class body can be optional: this is a declaration /** bq. See [Object expressions and Declarations] */ diff --git a/grammar/src/expressions.grm b/grammar/src/expressions.grm index 2b3b21af0c5..fafe44f37f0 100644 --- a/grammar/src/expressions.grm +++ b/grammar/src/expressions.grm @@ -235,7 +235,7 @@ jump // Ambiguity when after a SimpleName (infix call). In this case (e) is treated as an expression in parentheses // to put a tuple, write write ((e)) tupleLiteral - : "(" ((SimpleName "=")? expression){","} ")" + : "(" (((SimpleName "=")? expression){","})? ")" ; // one can use "it" as a parameter name diff --git a/grammar/src/when.grm b/grammar/src/when.grm index ebdbcc58502..d6769712963 100644 --- a/grammar/src/when.grm +++ b/grammar/src/when.grm @@ -45,7 +45,7 @@ constantPattern ; tuplePattern - : "(" ((SimpleName "=")? pattern{","})? ")" + : "(" (((SimpleName "=")? pattern){","})? ")" ; bindingPattern diff --git a/idea/src/jet/Library.jet b/idea/src/jet/Library.jet index 9fbf46d6e81..211e49cf2db 100644 --- a/idea/src/jet/Library.jet +++ b/idea/src/jet/Library.jet @@ -100,7 +100,7 @@ class IntRange> : Range, Iterable { } -class Number : Hashable { +abstract class Number : Hashable { abstract val dbl : Double abstract val flt : Float abstract val lng : Long diff --git a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java index 1821351ec89..ee82fb84c52 100644 --- a/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java +++ b/idea/src/org/jetbrains/jet/lang/JetSemanticServices.java @@ -50,11 +50,6 @@ public class JetSemanticServices { return new JetTypeInferrer(flowInformationProvider, this).getServices(trace); } -// @NotNull -// public ErrorHandler getErrorHandler() { -// return errorHandler; -// } -// @NotNull public JetTypeChecker getTypeChecker() { return typeChecker; diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetAnnotationEntry.java b/idea/src/org/jetbrains/jet/lang/psi/JetAnnotationEntry.java index 6c5dfb4cb82..8971900a36e 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetAnnotationEntry.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetAnnotationEntry.java @@ -32,6 +32,12 @@ public class JetAnnotationEntry extends JetElement implements JetCall { return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); } + @Override + public JetExpression getCalleeExpression() { + // Make callee an expression instead of a type reference + throw new UnsupportedOperationException(); // TODO + } + @Override public JetValueArgumentList getValueArgumentList() { return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST); diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetCall.java b/idea/src/org/jetbrains/jet/lang/psi/JetCall.java index 6a40027884a..58a62ef1679 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetCall.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetCall.java @@ -10,6 +10,9 @@ import java.util.List; * @author abreslav */ public interface JetCall extends PsiElement { + @Nullable + JetExpression getCalleeExpression(); + @Nullable JetValueArgumentList getValueArgumentList(); diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetCallExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetCallExpression.java index f49ff0c8dbe..33ae21cf505 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetCallExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetCallExpression.java @@ -26,6 +26,7 @@ public class JetCallExpression extends JetExpression implements JetCall { return visitor.visitCallExpression(this, data); } + @Override @Nullable public JetExpression getCalleeExpression() { return findChildByClass(JetExpression.class); diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java index 0f4db427370..0fee55e31ec 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToSuperCall.java @@ -26,6 +26,13 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements J return visitor.visitDelegationToSuperCallSpecifier(this, data); } + @NotNull + @Override + public JetExpression getCalleeExpression() { + // Change the AST so the the callee is an expression + throw new UnsupportedOperationException(); // TODO + } + @Nullable public JetValueArgumentList getValueArgumentList() { return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST); diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java index 6e0bb69ba46..c06b8e216b1 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDelegatorToThisCall.java @@ -27,6 +27,11 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier implements Je return visitor.visitDelegationToThisCall(this, data); } + @Override + public JetExpression getCalleeExpression() { + return getThisReference(); + } + @Nullable public JetValueArgumentList getValueArgumentList() { return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java index 8b13a6c03d5..1c466051715 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/AnalyzingUtils.java @@ -52,7 +52,7 @@ public class AnalyzingUtils { e.printStackTrace(); BindingTraceContext bindingTraceContext = new BindingTraceContext(); bindingTraceContext.getErrorHandler().genericError(file.getNode(), e.getClass().getSimpleName() + ": " + e.getMessage()); - return new Result(bindingTraceContext, PsiModificationTracker.MODIFICATION_COUNT); + return new Result(bindingTraceContext.getBindingContext(), PsiModificationTracker.MODIFICATION_COUNT); } } } @@ -112,7 +112,7 @@ public class AnalyzingUtils { throw new IllegalStateException("Must be guaranteed not to happen by the parser"); } }, Collections.singletonList(namespace)); - return bindingTraceContext; + return bindingTraceContext.getBindingContext(); } public static void applyHandler(@NotNull ErrorHandler errorHandler, @NotNull BindingContext bindingContext) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index b629e475a75..c20ecfc4aea 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -20,7 +20,7 @@ import java.util.*; /** * @author abreslav */ -public class BindingTraceContext implements BindingContext, BindingTrace { +public class BindingTraceContext implements BindingTrace { private final Map expressionTypes = new HashMap(); private final Map resolutionResults = new HashMap(); private final Map labelResolutionResults = new HashMap(); @@ -46,6 +46,169 @@ public class BindingTraceContext implements BindingContext, BindingTrace { private Map annotationDescriptos = Maps.newHashMap(); private Map> compileTimeValues = Maps.newHashMap(); + private final BindingContext bindingContext = new BindingContext() { + @Override + public DeclarationDescriptor getDeclarationDescriptor(PsiElement declaration) { + if (declaration instanceof JetNamespace) { + JetNamespace namespace = (JetNamespace) declaration; + return getNamespaceDescriptor(namespace); + } + return declarationsToDescriptors.get(declaration); + } + + public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) { + return namespaceDeclarationsToDescriptors.get(declaration); + } + + @Override + public ClassDescriptor getClassDescriptor(JetClassOrObject declaration) { + return (ClassDescriptor) declarationsToDescriptors.get((JetDeclaration) declaration); + } + + @Override + public TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter declaration) { + return (TypeParameterDescriptor) declarationsToDescriptors.get(declaration); + } + + @Override + public FunctionDescriptor getFunctionDescriptor(JetNamedFunction declaration) { + return (FunctionDescriptor) declarationsToDescriptors.get(declaration); + } + + @Override + public VariableDescriptor getVariableDescriptor(JetProperty declaration) { + return (VariableDescriptor) declarationsToDescriptors.get(declaration); + } + + @Override + public VariableDescriptor getVariableDescriptor(JetParameter declaration) { + return (VariableDescriptor) declarationsToDescriptors.get(declaration); + } + + @Override + public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) { + return primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter); + } + + @Override + public PropertyDescriptor getPropertyDescriptor(JetObjectDeclarationName objectDeclarationName) { + return (PropertyDescriptor) declarationsToDescriptors.get(objectDeclarationName); + } + + @Nullable + @Override + public ConstructorDescriptor getConstructorDescriptor(@NotNull JetElement declaration) { + return constructorDeclarationsToDescriptors.get(declaration); + } + + @Override + public AnnotationDescriptor getAnnotationDescriptor(JetAnnotationEntry annotationEntry) { + return annotationDescriptos.get(annotationEntry); + } + + @Override + public CompileTimeConstant getCompileTimeValue(JetExpression expression) { + return compileTimeValues.get(expression); + } + + @Override + public JetType resolveTypeReference(JetTypeReference typeReference) { + return types.get(typeReference); + } + + @Override + public JetType getExpressionType(JetExpression expression) { + return expressionTypes.get(expression); + } + + @Override + public DeclarationDescriptor resolveReferenceExpression(JetReferenceExpression referenceExpression) { + return resolutionResults.get(referenceExpression); + } + + @Override + public PsiElement resolveToDeclarationPsiElement(JetReferenceExpression referenceExpression) { + DeclarationDescriptor declarationDescriptor = resolveReferenceExpression(referenceExpression); + if (declarationDescriptor == null) { + return labelResolutionResults.get(referenceExpression); + } + return descriptorToDeclarations.get(getOriginal(declarationDescriptor)); + } + + @Override + public PsiElement getDeclarationPsiElement(@NotNull DeclarationDescriptor descriptor) { + return descriptorToDeclarations.get(getOriginal(descriptor)); + } + + @Override + public boolean isBlock(JetFunctionLiteralExpression expression) { + return !expression.getFunctionLiteral().hasParameterSpecification() && blocks.contains(expression); + } + + @Override + public boolean isStatement(@NotNull JetExpression expression) { + return statements.contains(expression); + } + + @Override + public boolean hasBackingField(@NotNull PropertyDescriptor propertyDescriptor) { + PsiElement declarationPsiElement = getDeclarationPsiElement(propertyDescriptor); + if (declarationPsiElement instanceof JetParameter) { + JetParameter jetParameter = (JetParameter) declarationPsiElement; + return jetParameter.getValOrVarNode() != null || + backingFieldRequired.contains(propertyDescriptor); + } + if (propertyDescriptor.getModifiers().isAbstract()) return false; + PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); + PropertySetterDescriptor setter = propertyDescriptor.getSetter(); + if (getter == null) { + return true; + } + else if (propertyDescriptor.isVar() && setter == null) { + return true; + } + else if (setter != null && !setter.hasBody() && !setter.getModifiers().isAbstract()) { + return true; + } + else if (!getter.hasBody() && !getter.getModifiers().isAbstract()) { + return true; + } + return backingFieldRequired.contains(propertyDescriptor); + } + + @Override + public boolean isVariableReassignment(JetExpression expression) { + return variableReassignments.contains(expression); + } + + public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall) { + JetTypeReference typeReference = superCall.getTypeReference(); + if (typeReference == null) return null; + + JetTypeElement typeElement = typeReference.getTypeElement(); + if (!(typeElement instanceof JetUserType)) return null; + + DeclarationDescriptor descriptor = resolveReferenceExpression(((JetUserType) typeElement).getReferenceExpression()); + return descriptor instanceof ConstructorDescriptor ? (ConstructorDescriptor) descriptor : null; + } + + @Override + public JetType getAutoCastType(@NotNull JetExpression expression) { + return autoCasts.get(expression); + } + + @Override + public JetScope getResolutionScope(@NotNull JetExpression expression) { + return resolutionScopes.get(expression); + } + + @Override + public Collection getDiagnostics() { + return diagnostics; + } + + }; + public BindingTraceContext() { } @@ -72,6 +235,11 @@ public class BindingTraceContext implements BindingContext, BindingTrace { diagnostics.addAll(other.diagnostics); } + @Override + public BindingContext getBindingContext() { + return bindingContext; + } + private void safePutAll(Map my, Map other) { assert keySetIntersection(my, other).isEmpty() : keySetIntersection(my, other); @@ -84,7 +252,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace { return keySet; } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @NotNull @@ -196,97 +363,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace { statements.remove(statement); } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - - @Override - public DeclarationDescriptor getDeclarationDescriptor(PsiElement declaration) { - if (declaration instanceof JetNamespace) { - JetNamespace namespace = (JetNamespace) declaration; - return getNamespaceDescriptor(namespace); - } - return declarationsToDescriptors.get(declaration); - } - - public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) { - return namespaceDeclarationsToDescriptors.get(declaration); - } - - @Override - public ClassDescriptor getClassDescriptor(JetClassOrObject declaration) { - return (ClassDescriptor) declarationsToDescriptors.get((JetDeclaration) declaration); - } - - @Override - public TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter declaration) { - return (TypeParameterDescriptor) declarationsToDescriptors.get(declaration); - } - - @Override - public FunctionDescriptor getFunctionDescriptor(JetNamedFunction declaration) { - return (FunctionDescriptor) declarationsToDescriptors.get(declaration); - } - - @Override - public VariableDescriptor getVariableDescriptor(JetProperty declaration) { - return (VariableDescriptor) declarationsToDescriptors.get(declaration); - } - - @Override - public VariableDescriptor getVariableDescriptor(JetParameter declaration) { - return (VariableDescriptor) declarationsToDescriptors.get(declaration); - } - - @Override - public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) { - return primaryConstructorParameterDeclarationsToPropertyDescriptors.get(primaryConstructorParameter); - } - - @Override - public PropertyDescriptor getPropertyDescriptor(JetObjectDeclarationName objectDeclarationName) { - return (PropertyDescriptor) declarationsToDescriptors.get(objectDeclarationName); - } - - @Nullable - @Override - public ConstructorDescriptor getConstructorDescriptor(@NotNull JetElement declaration) { - return constructorDeclarationsToDescriptors.get(declaration); - } - - @Override - public AnnotationDescriptor getAnnotationDescriptor(JetAnnotationEntry annotationEntry) { - return annotationDescriptos.get(annotationEntry); - } - - @Override - public CompileTimeConstant getCompileTimeValue(JetExpression expression) { - return compileTimeValues.get(expression); - } - - @Override - public JetType resolveTypeReference(JetTypeReference typeReference) { - return types.get(typeReference); - } - - @Override - public JetType getExpressionType(JetExpression expression) { - return expressionTypes.get(expression); - } - - @Override - public DeclarationDescriptor resolveReferenceExpression(JetReferenceExpression referenceExpression) { - return resolutionResults.get(referenceExpression); - } - - @Override - public PsiElement resolveToDeclarationPsiElement(JetReferenceExpression referenceExpression) { - DeclarationDescriptor declarationDescriptor = resolveReferenceExpression(referenceExpression); - if (declarationDescriptor == null) { - return labelResolutionResults.get(referenceExpression); - } - return descriptorToDeclarations.get(getOriginal(declarationDescriptor)); - } - private DeclarationDescriptor getOriginal(DeclarationDescriptor declarationDescriptor) { if (declarationDescriptor instanceof VariableAsFunctionDescriptor) { VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) declarationDescriptor; @@ -295,78 +371,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace { return declarationDescriptor.getOriginal(); } - @Override - public PsiElement getDeclarationPsiElement(@NotNull DeclarationDescriptor descriptor) { - return descriptorToDeclarations.get(getOriginal(descriptor)); - } - - @Override - public boolean isBlock(JetFunctionLiteralExpression expression) { - return !expression.getFunctionLiteral().hasParameterSpecification() && blocks.contains(expression); - } - - @Override - public boolean isStatement(@NotNull JetExpression expression) { - return statements.contains(expression); - } - - @Override - public boolean hasBackingField(@NotNull PropertyDescriptor propertyDescriptor) { - PsiElement declarationPsiElement = getDeclarationPsiElement(propertyDescriptor); - if (declarationPsiElement instanceof JetParameter) { - JetParameter jetParameter = (JetParameter) declarationPsiElement; - return jetParameter.getValOrVarNode() != null || - backingFieldRequired.contains(propertyDescriptor); - } - if (propertyDescriptor.getModifiers().isAbstract()) return false; - PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); - PropertySetterDescriptor setter = propertyDescriptor.getSetter(); - if (getter == null) { - return true; - } - else if (propertyDescriptor.isVar() && setter == null) { - return true; - } - else if (setter != null && !setter.hasBody() && !setter.getModifiers().isAbstract()) { - return true; - } - else if (!getter.hasBody() && !getter.getModifiers().isAbstract()) { - return true; - } - return backingFieldRequired.contains(propertyDescriptor); - } - - @Override - public boolean isVariableReassignment(JetExpression expression) { - return variableReassignments.contains(expression); - } - - public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall) { - JetTypeReference typeReference = superCall.getTypeReference(); - if (typeReference == null) return null; - - JetTypeElement typeElement = typeReference.getTypeElement(); - if (!(typeElement instanceof JetUserType)) return null; - - DeclarationDescriptor descriptor = resolveReferenceExpression(((JetUserType) typeElement).getReferenceExpression()); - return descriptor instanceof ConstructorDescriptor ? (ConstructorDescriptor) descriptor : null; - } - - @Override - public JetType getAutoCastType(@NotNull JetExpression expression) { - return autoCasts.get(expression); - } - - @Override - public JetScope getResolutionScope(@NotNull JetExpression expression) { - return resolutionScopes.get(expression); - } - - @Override - public Collection getDiagnostics() { - return diagnostics; - } - @Override public void markAsProcessed(@NotNull JetExpression expression) { processed.add(expression); @@ -377,8 +381,4 @@ public class BindingTraceContext implements BindingContext, BindingTrace { return processed.contains(expression); } - @Override - public BindingContext getBindingContext() { - return this; - } } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ChildBindingTrace.java b/idea/src/org/jetbrains/jet/lang/resolve/ChildBindingTrace.java new file mode 100644 index 00000000000..10888682477 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/resolve/ChildBindingTrace.java @@ -0,0 +1,254 @@ +package org.jetbrains.jet.lang.resolve; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.JetDiagnostic; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collection; + +/** + * @author abreslav + */ +public class ChildBindingTrace extends BindingTraceContext { + + private final BindingContext parentBindingContext; + + private final BindingContext bindingContext = new BindingContext() { + @Override + @Deprecated + public DeclarationDescriptor getDeclarationDescriptor(PsiElement declaration) { + DeclarationDescriptor value = ChildBindingTrace.super.getBindingContext().getDeclarationDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getDeclarationDescriptor(declaration); + } + + @Override + public NamespaceDescriptor getNamespaceDescriptor(JetNamespace declaration) { + NamespaceDescriptor value = ChildBindingTrace.super.getBindingContext().getNamespaceDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getNamespaceDescriptor(declaration); + } + + @Override + public ClassDescriptor getClassDescriptor(JetClassOrObject declaration) { + ClassDescriptor value = ChildBindingTrace.super.getBindingContext().getClassDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getClassDescriptor(declaration); + } + + @Override + public TypeParameterDescriptor getTypeParameterDescriptor(JetTypeParameter declaration) { + TypeParameterDescriptor value = ChildBindingTrace.super.getBindingContext().getTypeParameterDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getTypeParameterDescriptor(declaration); + } + + @Override + public FunctionDescriptor getFunctionDescriptor(JetNamedFunction declaration) { + FunctionDescriptor value = ChildBindingTrace.super.getBindingContext().getFunctionDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getFunctionDescriptor(declaration); + } + + @Override + public ConstructorDescriptor getConstructorDescriptor(JetElement declaration) { + ConstructorDescriptor value = ChildBindingTrace.super.getBindingContext().getConstructorDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getConstructorDescriptor(declaration); + } + + @Override + public AnnotationDescriptor getAnnotationDescriptor(JetAnnotationEntry annotationEntry) { + AnnotationDescriptor value = ChildBindingTrace.super.getBindingContext().getAnnotationDescriptor(annotationEntry); + if (value != null) { + return value; + } + return parentBindingContext.getAnnotationDescriptor(annotationEntry); + } + + @Override + @Nullable + public CompileTimeConstant getCompileTimeValue(JetExpression expression) { + return parentBindingContext.getCompileTimeValue(expression); + } + + @Override + public VariableDescriptor getVariableDescriptor(JetProperty declaration) { + VariableDescriptor value = ChildBindingTrace.super.getBindingContext().getVariableDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getVariableDescriptor(declaration); + } + + @Override + public VariableDescriptor getVariableDescriptor(JetParameter declaration) { + VariableDescriptor value = ChildBindingTrace.super.getBindingContext().getVariableDescriptor(declaration); + if (value != null) { + return value; + } + return parentBindingContext.getVariableDescriptor(declaration); + } + + @Override + public PropertyDescriptor getPropertyDescriptor(JetParameter primaryConstructorParameter) { + PropertyDescriptor value = ChildBindingTrace.super.getBindingContext().getPropertyDescriptor(primaryConstructorParameter); + if (value != null) { + return value; + } + return parentBindingContext.getPropertyDescriptor(primaryConstructorParameter); + } + + @Override + public PropertyDescriptor getPropertyDescriptor(JetObjectDeclarationName objectDeclarationName) { + PropertyDescriptor value = ChildBindingTrace.super.getBindingContext().getPropertyDescriptor(objectDeclarationName); + if (value != null) { + return value; + } + return parentBindingContext.getPropertyDescriptor(objectDeclarationName); + } + + @Override + public JetType getExpressionType(JetExpression expression) { + JetType value = ChildBindingTrace.super.getBindingContext().getExpressionType(expression); + if (value != null) { + return value; + } + return parentBindingContext.getExpressionType(expression); + } + + @Override + public DeclarationDescriptor resolveReferenceExpression(JetReferenceExpression referenceExpression) { + DeclarationDescriptor value = ChildBindingTrace.super.getBindingContext().resolveReferenceExpression(referenceExpression); + if (value != null) { + return value; + } + return parentBindingContext.resolveReferenceExpression(referenceExpression); + } + + @Override + public JetType resolveTypeReference(JetTypeReference typeReference) { + JetType value = ChildBindingTrace.super.getBindingContext().resolveTypeReference(typeReference); + if (value != null) { + return value; + } + return parentBindingContext.resolveTypeReference(typeReference); + } + + @Override + public PsiElement resolveToDeclarationPsiElement(JetReferenceExpression referenceExpression) { + PsiElement value = ChildBindingTrace.super.getBindingContext().resolveToDeclarationPsiElement(referenceExpression); + if (value != null) { + return value; + } + return parentBindingContext.resolveToDeclarationPsiElement(referenceExpression); + } + + @Override + public PsiElement getDeclarationPsiElement(DeclarationDescriptor descriptor) { + PsiElement value = ChildBindingTrace.super.getBindingContext().getDeclarationPsiElement(descriptor); + if (value != null) { + return value; + } + return parentBindingContext.getDeclarationPsiElement(descriptor); + } + + @Override + public boolean isBlock(JetFunctionLiteralExpression expression) { + boolean value = ChildBindingTrace.super.getBindingContext().isBlock(expression); + if (!value) { + return value; + } + return parentBindingContext.isBlock(expression); + } + + @Override + public boolean isStatement(JetExpression expression) { + boolean value = ChildBindingTrace.super.getBindingContext().isStatement(expression); + if (!value) { + return value; + } + return parentBindingContext.isStatement(expression); + } + + @Override + public boolean hasBackingField(PropertyDescriptor propertyDescriptor) { + boolean value = ChildBindingTrace.super.getBindingContext().hasBackingField(propertyDescriptor); + if (!value) { + return value; + } + return parentBindingContext.hasBackingField(propertyDescriptor); + } + + @Override + public boolean isVariableReassignment(JetExpression expression) { + boolean value = ChildBindingTrace.super.getBindingContext().isVariableReassignment(expression); + if (!value) { + return value; + } + return parentBindingContext.isVariableReassignment(expression); + } + + @Override + public ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall) { + ConstructorDescriptor value = ChildBindingTrace.super.getBindingContext().resolveSuperConstructor(superCall); + if (value != null) { + return value; + } + return parentBindingContext.resolveSuperConstructor(superCall); + } + + @Override + @Nullable + public JetType getAutoCastType(@NotNull JetExpression expression) { + JetType value = ChildBindingTrace.super.getBindingContext().getAutoCastType(expression); + if (value != null) { + return value; + } + return parentBindingContext.getAutoCastType(expression); + } + + @Override + @Nullable + public JetScope getResolutionScope(@NotNull JetExpression expression) { + JetScope value = ChildBindingTrace.super.getBindingContext().getResolutionScope(expression); + if (value != null) { + return value; + } + return parentBindingContext.getResolutionScope(expression); + } + + @Override + public Collection getDiagnostics() { + // This deliberately returns only my own diagnostics + return ChildBindingTrace.super.getBindingContext().getDiagnostics(); + } + }; + + public ChildBindingTrace(BindingContext parent) { + this.parentBindingContext = parent; + } + + @Override + public BindingContext getBindingContext() { + return parentBindingContext; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 9e3e747c234..f7ee75d5290 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -140,7 +140,7 @@ public class ClassDescriptorResolver { } descriptor.setTypeParameterDescriptors(typeParameters); - descriptor.setOpen(classElement.hasModifier(JetTokens.OPEN_KEYWORD)); + descriptor.setOpen(classElement.hasModifier(JetTokens.OPEN_KEYWORD) || classElement.hasModifier(JetTokens.ABSTRACT_KEYWORD)); trace.recordDeclarationResolution(classElement, descriptor); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java b/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java index db27c4cfa65..32ef6ae7b1b 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ScopeWithReceiver.java @@ -37,7 +37,7 @@ public class ScopeWithReceiver extends JetScopeImpl { // return false; // } // // TODO : in case of inferred type arguments, substitute the receiver type first -// return typeChecker.isSubtypeOf(receiverType, functionReceiverType); +// return typeChecker.startForPairOfTypes(receiverType, functionReceiverType); // } // }); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 567db243537..b6ad9bdfd55 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -31,7 +31,7 @@ public class TopDownAnalyzer { private final Map functions = Maps.newLinkedHashMap(); private final Map constructors = Maps.newLinkedHashMap(); - private final Map properties = new LinkedHashMap(); + private final Map properties = Maps.newLinkedHashMap(); private final Map declaringScopes = Maps.newHashMap(); private final Set primaryConstructorParameterProperties = Sets.newHashSet(); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index f31b5c56da5..29c67d84591 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -28,7 +28,8 @@ public class JetStandardLibrary { // private static final Map standardLibraryCache = new HashMap(); // TODO : double checked locking - synchronized public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) { + synchronized + public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) { if (cachedLibrary == null) { cachedLibrary = new JetStandardLibrary(project); } @@ -55,8 +56,8 @@ public class JetStandardLibrary { private final ClassDescriptor arrayClass; private final ClassDescriptor iterableClass; private final ClassDescriptor typeInfoClass; - private final JetType byteType; + private final JetType byteType; private final JetType charType; private final JetType shortType; private final JetType intType; @@ -86,7 +87,7 @@ public class JetStandardLibrary { // bootstrappingTDA.process(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace().getDeclarations()); bootstrappingTDA.processStandardLibraryNamespace(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace()); this.libraryScope = JetStandardClasses.STANDARD_CLASSES_NAMESPACE.getMemberScope(); - AnalyzingUtils.applyHandler(ErrorHandler.THROW_EXCEPTION, bindingTraceContext); + AnalyzingUtils.applyHandler(ErrorHandler.THROW_EXCEPTION, bindingTraceContext.getBindingContext()); this.byteClass = (ClassDescriptor) libraryScope.getClassifier("Byte"); this.charClass = (ClassDescriptor) libraryScope.getClassifier("Char"); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 11f7564f3d4..ba36527a44e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -313,28 +313,10 @@ public class JetTypeChecker { return false; } - public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { - if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) { - return true; - } - if (!supertype.isNullable() && subtype.isNullable()) { - return false; - } - if (JetStandardClasses.isNothing(subtype)) { - return true; - } - @Nullable JetType closestSupertype = findCorrespondingSupertype(subtype, supertype); - if (closestSupertype == null) { - return false; - } - - return checkSubtypeForTheSameConstructor(closestSupertype, supertype); - } - // This method returns the supertype of the first parameter that has the same constructor // as the second parameter, applying the substitution of type arguments to it @Nullable - private JetType findCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { + private static JetType findCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { TypeConstructor constructor = subtype.getConstructor(); if (constructor.equals(supertype.getConstructor())) { return subtype; @@ -348,75 +330,270 @@ public class JetTypeChecker { return null; } - private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) { - TypeConstructor constructor = subtype.getConstructor(); - assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor(); - - List subArguments = subtype.getArguments(); - List superArguments = supertype.getArguments(); - List parameters = constructor.getParameters(); - for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { - TypeParameterDescriptor parameter = parameters.get(i); - TypeProjection subArgument = subArguments.get(i); - TypeProjection superArgument = superArguments.get(i); - - JetType subArgumentType = subArgument.getType(); - JetType superArgumentType = superArgument.getType(); - switch (parameter.getVariance()) { - case INVARIANT: - switch (superArgument.getProjectionKind()) { - case INVARIANT: - if (!subArgumentType.equals(superArgumentType)) { - return false; - } - break; - case OUT_VARIANCE: - if (!subArgument.getProjectionKind().allowsOutPosition()) { - return false; - } - if (!isSubtypeOf(subArgumentType, superArgumentType)) { - return false; - } - break; - case IN_VARIANCE: - if (!subArgument.getProjectionKind().allowsInPosition()) { - return false; - } - if (!isSubtypeOf(superArgumentType, subArgumentType)) { - return false; - } - break; - } - break; - case IN_VARIANCE: - switch (superArgument.getProjectionKind()) { - case INVARIANT: - case IN_VARIANCE: - if (!isSubtypeOf(superArgumentType, subArgumentType)) { - return false; - } - break; - case OUT_VARIANCE: - if (!isSubtypeOf(subArgumentType, superArgumentType)) { - return false; - } - break; - } - break; - case OUT_VARIANCE: - switch (superArgument.getProjectionKind()) { - case INVARIANT: - case OUT_VARIANCE: - case IN_VARIANCE: - if (!isSubtypeOf(subArgumentType, superArgumentType)) { - return false; - } - break; - } - break; - } - } - return true; + public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { + return new TypeCheckingProcedure().run(subtype, supertype); } + private static class OldProcedure { + public static boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) { + if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) { + return true; + } + if (!supertype.isNullable() && subtype.isNullable()) { + return false; + } + if (JetStandardClasses.isNothing(subtype)) { + return true; + } + @Nullable JetType closestSupertype = findCorrespondingSupertype(subtype, supertype); + if (closestSupertype == null) { + return false; + } + + return checkSubtypeForTheSameConstructor(closestSupertype, supertype); + } + + private static boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) { + TypeConstructor constructor = subtype.getConstructor(); + assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor(); + + List subArguments = subtype.getArguments(); + List superArguments = supertype.getArguments(); + List parameters = constructor.getParameters(); + boolean status = true; + for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { + TypeParameterDescriptor parameter = parameters.get(i); + TypeProjection subArgument = subArguments.get(i); + TypeProjection superArgument = superArguments.get(i); + + JetType subArgumentType = subArgument.getType(); + JetType superArgumentType = superArgument.getType(); + switch (parameter.getVariance()) { + case INVARIANT: + switch (superArgument.getProjectionKind()) { + case INVARIANT: + status = subArgumentType.equals(superArgumentType); + break; + case OUT_VARIANCE: + if (!subArgument.getProjectionKind().allowsOutPosition()) { + status = false; + } else { + status = !isSubtypeOf(subArgumentType, superArgumentType); + } + break; + case IN_VARIANCE: + if (!subArgument.getProjectionKind().allowsInPosition()) { + status = false; + } else { + status = isSubtypeOf(superArgumentType, subArgumentType); + } + break; + } + break; + case IN_VARIANCE: + switch (superArgument.getProjectionKind()) { + case INVARIANT: + case IN_VARIANCE: + status = isSubtypeOf(superArgumentType, subArgumentType); + break; + case OUT_VARIANCE: + status = isSubtypeOf(subArgumentType, superArgumentType); + break; + } + break; + case OUT_VARIANCE: + switch (superArgument.getProjectionKind()) { + case INVARIANT: + case OUT_VARIANCE: + case IN_VARIANCE: + status = isSubtypeOf(subArgumentType, superArgumentType); + break; + } + break; + } + if (!status) { + return false; + } + } + return true; + } + } + + public static abstract class AbstractTypeCheckingProcedure { + + protected enum StatusAction { + PROCEED(false), + DONE_WITH_CURRENT_TYPE(true), + ABORT_ALL(true); + + private final boolean abort; + + private StatusAction(boolean abort) { + this.abort = abort; + } + + public boolean isAbort() { + return abort; + } + } + + public final T run(@NotNull JetType subtype, @NotNull JetType supertype) { + proceedOrStop(subtype, supertype); + return result(); + } + + protected abstract StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype); + + protected abstract StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype); + + protected abstract StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType); + + protected abstract StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument); + + protected abstract StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype); + + protected abstract T result(); + + private StatusAction proceedOrStop(@NotNull JetType subtype, @NotNull JetType supertype) { + StatusAction statusAction = startForPairOfTypes(subtype, supertype); + if (statusAction.isAbort()) { + return statusAction; + } + + JetType closestSupertype = findCorrespondingSupertype(subtype, supertype); + if (closestSupertype == null) { + return noCorrespondingSupertype(subtype, supertype); + } + + proceed(closestSupertype, supertype); + return doneForPairOfTypes(subtype, supertype); + } + + private void proceed(@NotNull JetType subtype, @NotNull JetType supertype) { + TypeConstructor constructor = subtype.getConstructor(); + assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor(); + + List subArguments = subtype.getArguments(); + List superArguments = supertype.getArguments(); + List parameters = constructor.getParameters(); + + loop: + for (int i = 0; i < parameters.size(); i++) { + TypeParameterDescriptor parameter = parameters.get(i); + TypeProjection subArgument = subArguments.get(i); + TypeProjection superArgument = superArguments.get(i); + + JetType subArgumentType = subArgument.getType(); + JetType superArgumentType = superArgument.getType(); + + StatusAction action = null; + switch (parameter.getVariance()) { + case INVARIANT: + switch (superArgument.getProjectionKind()) { + case INVARIANT: + action = equalTypesRequired(subArgumentType, superArgumentType); + break; + case OUT_VARIANCE: + if (!subArgument.getProjectionKind().allowsOutPosition()) { + action = varianceConflictFound(subArgument, superArgument); + } + else { + action = proceedOrStop(subArgumentType, superArgumentType); + } + break; + case IN_VARIANCE: + if (!subArgument.getProjectionKind().allowsInPosition()) { + action = varianceConflictFound(subArgument, superArgument); + } + else { + action = proceedOrStop(superArgumentType, subArgumentType); + } + break; + } + break; + case IN_VARIANCE: + switch (superArgument.getProjectionKind()) { + case INVARIANT: + case IN_VARIANCE: + action = proceedOrStop(superArgumentType, subArgumentType); + break; + case OUT_VARIANCE: + action = proceedOrStop(subArgumentType, superArgumentType); + break; + } + break; + case OUT_VARIANCE: + switch (superArgument.getProjectionKind()) { + case INVARIANT: + case OUT_VARIANCE: + case IN_VARIANCE: + action = proceedOrStop(subArgumentType, superArgumentType); + break; + } + break; + } + switch (action) { + case ABORT_ALL: break loop; + case DONE_WITH_CURRENT_TYPE: + default: + } + } + } + + } + + + private static class TypeCheckingProcedure extends AbstractTypeCheckingProcedure { + + private boolean result = true; + + private StatusAction fail() { + result = false; + return StatusAction.ABORT_ALL; + } + + @Override + public StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { + if (ErrorUtils.isErrorType(subtype) || ErrorUtils.isErrorType(supertype)) { + return StatusAction.DONE_WITH_CURRENT_TYPE; + } + if (!supertype.isNullable() && subtype.isNullable()) { + return fail(); + } + if (JetStandardClasses.isNothing(subtype)) { + return StatusAction.DONE_WITH_CURRENT_TYPE; + } + return StatusAction.PROCEED; + } + + @Override + protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { + return fail(); + } + + @Override + protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) { + if (!subArgumentType.equals(superArgumentType)) { + return fail(); + } + return StatusAction.PROCEED; + } + + @Override + protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) { + return fail(); + } + + @Override + protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { + return StatusAction.PROCEED; + } + + @Override + protected Boolean result() { + return result; + } + + + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 4c201d48c4c..efe39889cdc 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -20,6 +20,7 @@ import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver; import org.jetbrains.jet.lang.resolve.constants.ErrorValue; +import org.jetbrains.jet.lang.types.inference.ConstraintSystem; import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.resolve.DescriptorRenderer; import org.jetbrains.jet.lang.resolve.constants.StringValue; @@ -533,6 +534,71 @@ public class JetTypeInferrer { return result; } + @Nullable + private JetType resolveCall( + @NotNull JetScope scope, + @NotNull JetCall call, + @NotNull JetType expectedType + ) { + if (call.getTypeArguments().isEmpty()) { + JetExpression calleeExpression = call.getCalleeExpression(); + Collection candidates; + if (calleeExpression instanceof JetSimpleNameExpression) { + JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression; + candidates = scope.getFunctionGroup(expression.getReferencedName()).getFunctionDescriptors(); + } + else { + throw new UnsupportedOperationException("Type argument inference not implemented"); + } + + assert candidates.size() == 1; + + FunctionDescriptor candidate = candidates.iterator().next(); + + assert candidate.getTypeParameters().size() == call.getTypeArguments().size(); + + ConstraintSystem constraintSystem = new ConstraintSystem(); + for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) { + constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO + } + + Iterator parameters = candidate.getValueParameters().iterator(); + for (JetValueArgument valueArgument : call.getValueArguments()) { + assert !valueArgument.isNamed(); + ValueParameterDescriptor valueParameterDescriptor = parameters.next(); + JetExpression expression = valueArgument.getArgumentExpression(); + JetType type = getType(scope, expression, false, NO_EXPECTED_TYPE); + constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType()); + } + + if (expectedType != NO_EXPECTED_TYPE) { + System.out.println("expectedType = " + expectedType); + constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType); + } + + ConstraintSystem.Solution solution = constraintSystem.solve(); + if (!solution.isSuccessful()) { + trace.getErrorHandler().genericError(calleeExpression.getNode(), "Type inference failed"); +// for (Inconsistency inconsistency : solution.getInconsistencies()) { +// System.out.println("inconsistency = " + inconsistency); +// } + return null; + } + else { + for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) { + JetType value = solution.getValue(typeParameterDescriptor); + System.out.println("typeParameterDescriptor = " + typeParameterDescriptor); + System.out.println("value = " + value); + } + return solution.getSubstitutor().substitute(candidate.getReturnType(), Variance.INVARIANT); // TODO + } +// return null; + } + else { + throw new UnsupportedOperationException("Explicit type arguments not implemented"); + } + } + @Nullable private JetType resolveCall( @NotNull JetScope scope, @@ -2230,6 +2296,7 @@ public class JetTypeInferrer { @Override public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) { +// return context.services.checkType(context.services.resolveCall(context.scope, expression, context.expectedType), expression, context); return context.services.checkType(getCallExpressionType(null, expression, context), expression, context); } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index 8894d010bfb..441054b7b3f 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -15,6 +15,30 @@ import java.util.Map; */ public class TypeSubstitutor { + public interface TypeSubstitution { + @Nullable + TypeProjection get(TypeConstructor key); + boolean isEmpty(); + } + + public static class MapToTypeSubstitutionAdapter implements TypeSubstitution { + private final @NotNull Map substitutionContext; + + public MapToTypeSubstitutionAdapter(@NotNull Map substitutionContext) { + this.substitutionContext = substitutionContext; + } + + @Override + public TypeProjection get(TypeConstructor key) { + return substitutionContext.get(key); + } + + @Override + public boolean isEmpty() { + return substitutionContext.isEmpty(); + } + } + public static final TypeSubstitutor EMPTY = create(Collections.emptyMap()); public static final class SubstitutionException extends Exception { @@ -23,8 +47,12 @@ public class TypeSubstitutor { } } + public static TypeSubstitutor create(@NotNull TypeSubstitution substitution) { + return new TypeSubstitutor(substitution); + } + public static TypeSubstitutor create(@NotNull Map substitutionContext) { - return new TypeSubstitutor(substitutionContext); + return create(new MapToTypeSubstitutionAdapter(substitutionContext)); } public static TypeSubstitutor create(@NotNull JetType context) { @@ -33,9 +61,9 @@ public class TypeSubstitutor { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - private final @NotNull Map substitutionContext; + private final @NotNull TypeSubstitution substitutionContext; - private TypeSubstitutor(@NotNull Map substitutionContext) { + private TypeSubstitutor(@NotNull TypeSubstitution substitutionContext) { this.substitutionContext = substitutionContext; } @@ -109,7 +137,7 @@ public class TypeSubstitutor { @NotNull private TypeProjection substituteInProjection( - @NotNull Map substitutionContext, + @NotNull TypeSubstitution substitutionContext, @NotNull TypeProjection passedProjection, @NotNull TypeParameterDescriptor correspondingTypeParameter, @NotNull Variance contextCallSiteVariance) throws SubstitutionException { @@ -181,10 +209,6 @@ public class TypeSubstitutor { return new TypeProjection(effectiveProjectionKindValue, specializeType(effectiveTypeValue, effectiveContextVariance)); } - /*package*/ void addSubstitution(@NotNull TypeConstructor typeConstructor, @NotNull TypeProjection typeProjection) { - substitutionContext.put(typeConstructor, typeProjection); - } - private static Variance asymmetricOr(Variance a, Variance b) { return a == Variance.INVARIANT ? b : a; } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java index 7e6318ad190..c20be85a0c1 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -50,6 +50,9 @@ public class TypeUtils { StringBuilder debugName = new StringBuilder(); boolean nullable = false; + Set resultingTypes = Sets.newHashSet(); + + outer: for (Iterator iterator = types.iterator(); iterator.hasNext();) { JetType type = iterator.next(); @@ -63,9 +66,17 @@ public class TypeUtils { } return type; } + else { + for (JetType other : types) { + if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) { + continue outer; + } + } + } nullable |= type.isNullable(); + resultingTypes.add(type); debugName.append(type.toString()); if (iterator.hasNext()) { debugName.append(" & "); @@ -79,11 +90,11 @@ public class TypeUtils { false, debugName.toString(), Collections.emptyList(), - types); + resultingTypes); - JetScope[] scopes = new JetScope[types.size()]; + JetScope[] scopes = new JetScope[resultingTypes.size()]; int i = 0; - for (JetType type : types) { + for (JetType type : resultingTypes) { scopes[i] = type.getMemberScope(); i++; } @@ -217,12 +228,15 @@ public class TypeUtils { */ @NotNull public static TypeSubstitutor buildDeepSubstitutor(@NotNull JetType type) { - TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(Maps.newHashMap()); - fillInDeepSubstitutor(type, typeSubstitutor); + HashMap substitution = Maps.newHashMap(); + TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution); + // we use the mutability of the map here + fillInDeepSubstitutor(type, typeSubstitutor, substitution); return typeSubstitutor; } - private static void fillInDeepSubstitutor(JetType context, TypeSubstitutor substitutor) { + // we use the mutability of the substitution map here + private static void fillInDeepSubstitutor(JetType context, TypeSubstitutor substitutor, Map substitution) { List parameters = context.getConstructor().getParameters(); List arguments = context.getArguments(); for (int i = 0; i < arguments.size(); i++) { @@ -232,10 +246,10 @@ public class TypeUtils { JetType substitute = substitutor.substitute(argument.getType(), Variance.INVARIANT); assert substitute != null; TypeProjection substitutedTypeProjection = new TypeProjection(argument.getProjectionKind(), substitute); - substitutor.addSubstitution(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection); + substitution.put(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection); } for (JetType supertype : context.getConstructor().getSupertypes()) { - fillInDeepSubstitutor(supertype, substitutor); + fillInDeepSubstitutor(supertype, substitutor, substitution); } } diff --git a/idea/src/org/jetbrains/jet/lang/types/Variance.java b/idea/src/org/jetbrains/jet/lang/types/Variance.java index 4f1cdd3f281..b384b839eea 100644 --- a/idea/src/org/jetbrains/jet/lang/types/Variance.java +++ b/idea/src/org/jetbrains/jet/lang/types/Variance.java @@ -38,6 +38,18 @@ public enum Variance { throw new IllegalStateException(); } + public Variance opposite() { + switch (this) { + case INVARIANT: + return INVARIANT; + case IN_VARIANCE: + return OUT_VARIANCE; + case OUT_VARIANCE: + return IN_VARIANCE; + } + throw new IllegalStateException("Impossible variance: " + this); + } + @Override public String toString() { return label; diff --git a/idea/src/org/jetbrains/jet/lang/types/inference/ConstraintSystem.java b/idea/src/org/jetbrains/jet/lang/types/inference/ConstraintSystem.java new file mode 100644 index 00000000000..7e42f7d2939 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/inference/ConstraintSystem.java @@ -0,0 +1,415 @@ +package org.jetbrains.jet.lang.types.inference; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.types.*; + +import java.util.Map; +import java.util.Set; + +/** + * @author abreslav + */ +public class ConstraintSystem { + +// private static final Supplier> SET_SUPPLIER = new Supplier>() { +// @Override +// public Set get() { +// return Sets.newHashSet(); +// } +// }; + + private static class LoopInTypeVariableConstraintsException extends RuntimeException { + private LoopInTypeVariableConstraintsException() { + } + + private LoopInTypeVariableConstraintsException(String message) { + super(message); + } + + private LoopInTypeVariableConstraintsException(String message, Throwable cause) { + super(message, cause); + } + + private LoopInTypeVariableConstraintsException(Throwable cause) { + super(cause); + } + } + + public static abstract class TypeValue { + private final Set upperBounds = Sets.newHashSet(); + private final Set lowerBounds = Sets.newHashSet(); + + @NotNull + public Set getUpperBounds() { + return upperBounds; + } + + @NotNull + public Set getLowerBounds() { + return lowerBounds; + } + + @Nullable + public abstract KnownType getValue(); + } + + private static class UnknownType extends TypeValue { + + private final TypeParameterDescriptor typeParameterDescriptor; + private final Variance positionVariance; + private KnownType value; + private boolean beingComputed = false; + + private UnknownType(TypeParameterDescriptor typeParameterDescriptor, Variance positionVariance) { + this.typeParameterDescriptor = typeParameterDescriptor; + this.positionVariance = positionVariance; + } + + @NotNull + public TypeParameterDescriptor getTypeParameterDescriptor() { + return typeParameterDescriptor; + } + + @Override + public KnownType getValue() { + if (beingComputed) { + throw new LoopInTypeVariableConstraintsException(); + } + if (value == null) { + JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + beingComputed = true; + try { + if (positionVariance == Variance.IN_VARIANCE) { + // maximal solution + throw new UnsupportedOperationException(); + } + else { + // minimal solution + + Set lowerBounds = getLowerBounds(); + if (!lowerBounds.isEmpty()) { + Set types = getTypes(lowerBounds); + + JetType commonSupertype = typeChecker.commonSupertype(types); + for (TypeValue upperBound : getUpperBounds()) { + if (!typeChecker.isSubtypeOf(commonSupertype, upperBound.getValue().getType())) { + value = null; + } + } + + System.out.println("minimal solution from lowerbounds for " + this + " is " + commonSupertype); + value = new KnownType(commonSupertype); + } + else { + Set upperBounds = getUpperBounds(); + Set types = getTypes(upperBounds); + JetType intersect = TypeUtils.intersect(typeChecker, types); + + value = new KnownType(intersect); + } + } + } + finally { + beingComputed = false; + } + } + + return value; + } + + private Set getTypes(Set lowerBounds) { + Set types = Sets.newHashSet(); + for (TypeValue lowerBound : lowerBounds) { + types.add(lowerBound.getValue().getType()); + } + return types; + } + + @Override + public String toString() { + return "?" + typeParameterDescriptor; + } + + } + + private static class KnownType extends TypeValue { + + private final JetType type; + + public KnownType(@NotNull JetType type) { + this.type = type; + } + + @NotNull + public JetType getType() { + return type; + } + + @Override + public KnownType getValue() { + return this; + } + + @Override + public String toString() { + return type.toString(); + } + } + + private final Map knownTypes = Maps.newHashMap(); + private final Map unknownTypes = Maps.newHashMap(); + private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; + + @NotNull + private TypeValue getTypeValueFor(@NotNull JetType type) { + DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); + if (declarationDescriptor instanceof TypeParameterDescriptor) { + TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; + UnknownType unknownType = unknownTypes.get(typeParameterDescriptor); + if (unknownType != null) { + return unknownType; + } + } + + KnownType typeValue = knownTypes.get(type); + if (typeValue == null) { + typeValue = new KnownType(type); + knownTypes.put(type, typeValue); + } + return typeValue; + } + + public void registerTypeVariable(@NotNull TypeParameterDescriptor typeParameterDescriptor, @NotNull Variance positionVariance) { + assert !unknownTypes.containsKey(typeParameterDescriptor); + UnknownType typeValue = new UnknownType(typeParameterDescriptor, positionVariance); + unknownTypes.put(typeParameterDescriptor, typeValue); + } + + @NotNull + private UnknownType getTypeVariable(TypeParameterDescriptor typeParameterDescriptor) { + UnknownType unknownType = unknownTypes.get(typeParameterDescriptor); + if (unknownType == null) { + throw new IllegalArgumentException("This type parameter is not an unknown in this constraint system"); + } + return unknownType; + } + + public void addSubtypingConstraint(JetType lower, JetType upper) { + TypeValue typeValueForLower = getTypeValueFor(lower); + TypeValue typeValueForUpper = getTypeValueFor(upper); + addSubtypingConstraintOnTypeValues(typeValueForLower, typeValueForUpper); + } + + private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) { + System.out.println(typeValueForLower + " :< " + typeValueForUpper); + typeValueForLower.getUpperBounds().add(typeValueForUpper); + typeValueForUpper.getLowerBounds().add(typeValueForLower); + } + + @NotNull + public Solution solve() { + // Expand custom bounds, e.g. List <: List + for (Map.Entry entry : Sets.newHashSet(knownTypes.entrySet())) { + JetType jetType = entry.getKey(); + KnownType typeValue = entry.getValue(); + + for (TypeValue upperBound : typeValue.getUpperBounds()) { + if (upperBound instanceof KnownType) { + KnownType knownBoundType = (KnownType) upperBound; + boolean ok = new TypeConstraintExpander().run(jetType, knownBoundType.getType()); + if (!ok) { + return new Solution(true); + } + } + } + + // Lower bounds? + + } + + // Fill in upper bounds from type parameter bounds + for (Map.Entry entry : Sets.newHashSet(unknownTypes.entrySet())) { + TypeParameterDescriptor typeParameterDescriptor = entry.getKey(); + UnknownType typeValue = entry.getValue(); + for (JetType upperBound : typeParameterDescriptor.getUpperBounds()) { + addSubtypingConstraintOnTypeValues(typeValue, getTypeValueFor(upperBound)); + } + } + + // effective bounds for each node + Set visited = Sets.newHashSet(); + for (KnownType knownType : knownTypes.values()) { + transitiveClosure(knownType, visited); + } + for (UnknownType unknownType : unknownTypes.values()) { + transitiveClosure(unknownType, visited); + } + + // Find inconsistencies + Solution solution = new Solution(false); + + for (UnknownType unknownType : unknownTypes.values()) { + check(unknownType, solution); + } + for (KnownType knownType : knownTypes.values()) { + check(knownType, solution); + } + + return solution; + } + + private void check(TypeValue typeValue, Solution solution) { + try { + KnownType resultingValue = typeValue.getValue(); + JetType type = solution.getSubstitutor().substitute(resultingValue.getType(), Variance.INVARIANT); // TODO + for (TypeValue upperBound : typeValue.getUpperBounds()) { + JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT); + if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO + solution.registerError(); + System.out.println("Constraint violation: " + type + " :< " + boundingType); + } + } + for (TypeValue lowerBound : typeValue.getLowerBounds()) { + JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT); + if (!typeChecker.isSubtypeOf(boundingType, type)) { + solution.registerError(); + System.out.println("Constraint violation: " + boundingType + " :< " + type); + } + } + } + catch (LoopInTypeVariableConstraintsException e) { + solution.registerError(); + e.printStackTrace(); + } + } + + private void transitiveClosure(TypeValue current, Set visited) { + if (!visited.add(current)) { + return; + } + + for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) { + transitiveClosure(upperBound, visited); + Set upperBounds = upperBound.getUpperBounds(); + for (TypeValue transitiveBound : upperBounds) { + addSubtypingConstraintOnTypeValues(current, transitiveBound); + } + } + } + + public class Solution { + private final TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() { + @Override + public TypeProjection get(TypeConstructor key) { + DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor(); + if (declarationDescriptor instanceof TypeParameterDescriptor) { + TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor; + System.out.println(descriptor + " |-> " + getValue(descriptor)); + return new TypeProjection(getValue(descriptor)); + } + return null; + } + + @Override + public boolean isEmpty() { + return false; + } + }); + private boolean failed; + + public Solution(boolean failed) { + this.failed = failed; + } + + public void registerError() { + failed = true; + } + + public boolean isSuccessful() { + return !failed; + } + + @Nullable + public JetType getValue(TypeParameterDescriptor typeParameterDescriptor) { + KnownType value = getTypeVariable(typeParameterDescriptor).getValue(); + return value == null ? null : value.getType(); + } + + public TypeSubstitutor getSubstitutor() { + return typeSubstitutor; + } + + } + + private class TypeConstraintExpander extends JetTypeChecker.AbstractTypeCheckingProcedure { + + private boolean error = false; + + private StatusAction fail() { + error = true; + return StatusAction.ABORT_ALL; + } + + @Override + protected StatusAction startForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { + return tryToAddConstraint(subtype, supertype); + } + + private StatusAction tryToAddConstraint(@NotNull JetType subtype, @NotNull JetType supertype) { + TypeValue subtypeValue = getTypeValueFor(subtype); + TypeValue supertypeValue = getTypeValueFor(supertype); + + if (someUnknown(subtypeValue, supertypeValue)) { + addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue); + } + return StatusAction.PROCEED; + +// // both types are known +// if (typeChecker.isSubtypeOf(subtype, supertype)) { +// return StatusAction.PROCEED; +// } +// return fail(); + } + + private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) { + return subtypeValue instanceof UnknownType || supertypeValue instanceof UnknownType; + } + + @Override + protected StatusAction noCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) { + if (someUnknown(getTypeValueFor(subtype), getTypeValueFor(supertype))) { + return StatusAction.PROCEED; + } + return fail(); + } + + @Override + protected StatusAction equalTypesRequired(@NotNull JetType subArgumentType, @NotNull JetType superArgumentType) { + if (!subArgumentType.equals(superArgumentType)) { + return fail(); + } + return StatusAction.PROCEED; + } + + @Override + protected StatusAction varianceConflictFound(@NotNull TypeProjection subArgument, @NotNull TypeProjection superArgument) { + return fail(); + } + + @Override + protected StatusAction doneForPairOfTypes(@NotNull JetType subtype, @NotNull JetType supertype) { + return StatusAction.PROCEED; + } + + @Override + protected Boolean result() { + return !error; + } + } + +} \ No newline at end of file