Migrating BindingTraceContext to a transactional form

This commit is contained in:
Andrey Breslav
2011-08-17 21:21:44 +04:00
parent 9ebffafd89
commit a2b779fcd0
23 changed files with 1271 additions and 290 deletions
+1 -1
View File
@@ -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]
*/
+1 -1
View File
@@ -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
+1 -1
View File
@@ -45,7 +45,7 @@ constantPattern
;
tuplePattern
: "(" ((SimpleName "=")? pattern{","})? ")"
: "(" (((SimpleName "=")? pattern){","})? ")"
;
bindingPattern
+1 -1
View File
@@ -100,7 +100,7 @@ class IntRange<T : Comparable<T>> : Range<T>, Iterable<T> {
}
class Number : Hashable {
abstract class Number : Hashable {
abstract val dbl : Double
abstract val flt : Float
abstract val lng : Long
@@ -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;
@@ -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);
@@ -10,6 +10,9 @@ import java.util.List;
* @author abreslav
*/
public interface JetCall extends PsiElement {
@Nullable
JetExpression getCalleeExpression();
@Nullable
JetValueArgumentList getValueArgumentList();
@@ -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);
@@ -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);
@@ -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);
@@ -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<BindingContext>(bindingTraceContext, PsiModificationTracker.MODIFICATION_COUNT);
return new Result<BindingContext>(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.<JetDeclaration>singletonList(namespace));
return bindingTraceContext;
return bindingTraceContext.getBindingContext();
}
public static void applyHandler(@NotNull ErrorHandler errorHandler, @NotNull BindingContext bindingContext) {
@@ -20,7 +20,7 @@ import java.util.*;
/**
* @author abreslav
*/
public class BindingTraceContext implements BindingContext, BindingTrace {
public class BindingTraceContext implements BindingTrace {
private final Map<JetExpression, JetType> expressionTypes = new HashMap<JetExpression, JetType>();
private final Map<JetReferenceExpression, DeclarationDescriptor> resolutionResults = new HashMap<JetReferenceExpression, DeclarationDescriptor>();
private final Map<JetReferenceExpression, PsiElement> labelResolutionResults = new HashMap<JetReferenceExpression, PsiElement>();
@@ -46,6 +46,169 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
private Map<JetAnnotationEntry, AnnotationDescriptor> annotationDescriptos = Maps.newHashMap();
private Map<JetExpression, CompileTimeConstant<?>> 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<JetDiagnostic> 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 <K, V> void safePutAll(Map<K, V> my, Map<K, V> 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<JetDiagnostic> 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;
}
}
@@ -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<JetDiagnostic> 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;
}
}
@@ -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);
}
@@ -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);
// }
// });
}
@@ -31,7 +31,7 @@ public class TopDownAnalyzer {
private final Map<JetNamedFunction, FunctionDescriptorImpl> functions = Maps.newLinkedHashMap();
private final Map<JetDeclaration, ConstructorDescriptor> constructors = Maps.newLinkedHashMap();
private final Map<JetProperty, PropertyDescriptor> properties = new LinkedHashMap<JetProperty, PropertyDescriptor>();
private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap();
private final Map<JetDeclaration, JetScope> declaringScopes = Maps.newHashMap();
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet();
@@ -28,7 +28,8 @@ public class JetStandardLibrary {
// private static final Map<Project, JetStandardLibrary> standardLibraryCache = new HashMap<Project, JetStandardLibrary>();
// 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");
@@ -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<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments();
List<TypeParameterDescriptor> 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<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments();
List<TypeParameterDescriptor> 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<T> {
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<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments();
List<TypeParameterDescriptor> 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<Boolean> {
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;
}
}
}
@@ -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<FunctionDescriptor> 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<ValueParameterDescriptor> 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);
}
@@ -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<TypeConstructor, TypeProjection> substitutionContext;
public MapToTypeSubstitutionAdapter(@NotNull Map<TypeConstructor, TypeProjection> 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.<TypeConstructor, TypeProjection>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<TypeConstructor, TypeProjection> 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<TypeConstructor, TypeProjection> substitutionContext;
private final @NotNull TypeSubstitution substitutionContext;
private TypeSubstitutor(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext) {
private TypeSubstitutor(@NotNull TypeSubstitution substitutionContext) {
this.substitutionContext = substitutionContext;
}
@@ -109,7 +137,7 @@ public class TypeSubstitutor {
@NotNull
private TypeProjection substituteInProjection(
@NotNull Map<TypeConstructor, TypeProjection> 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;
}
@@ -50,6 +50,9 @@ public class TypeUtils {
StringBuilder debugName = new StringBuilder();
boolean nullable = false;
Set<JetType> resultingTypes = Sets.newHashSet();
outer:
for (Iterator<JetType> 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.<TypeParameterDescriptor>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.<TypeConstructor, TypeProjection>newHashMap());
fillInDeepSubstitutor(type, typeSubstitutor);
HashMap<TypeConstructor, TypeProjection> substitution = Maps.<TypeConstructor, TypeProjection>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<TypeConstructor, TypeProjection> substitution) {
List<TypeParameterDescriptor> parameters = context.getConstructor().getParameters();
List<TypeProjection> 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);
}
}
@@ -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;
@@ -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<TypeValue>> SET_SUPPLIER = new Supplier<Set<TypeValue>>() {
// @Override
// public Set<TypeValue> 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<TypeValue> upperBounds = Sets.newHashSet();
private final Set<TypeValue> lowerBounds = Sets.newHashSet();
@NotNull
public Set<TypeValue> getUpperBounds() {
return upperBounds;
}
@NotNull
public Set<TypeValue> 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<TypeValue> lowerBounds = getLowerBounds();
if (!lowerBounds.isEmpty()) {
Set<JetType> 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<TypeValue> upperBounds = getUpperBounds();
Set<JetType> types = getTypes(upperBounds);
JetType intersect = TypeUtils.intersect(typeChecker, types);
value = new KnownType(intersect);
}
}
}
finally {
beingComputed = false;
}
}
return value;
}
private Set<JetType> getTypes(Set<TypeValue> lowerBounds) {
Set<JetType> 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<JetType, KnownType> knownTypes = Maps.newHashMap();
private final Map<TypeParameterDescriptor, UnknownType> 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<T> <: List<Int>
for (Map.Entry<JetType, KnownType> 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<TypeParameterDescriptor, UnknownType> 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<TypeValue> 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<TypeValue> visited) {
if (!visited.add(current)) {
return;
}
for (TypeValue upperBound : Sets.newHashSet(current.getUpperBounds())) {
transitiveClosure(upperBound, visited);
Set<TypeValue> 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<Boolean> {
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;
}
}
}