Migrating BindingTraceContext to a transactional form
This commit is contained in:
@@ -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]
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -45,7 +45,7 @@ constantPattern
|
||||
;
|
||||
|
||||
tuplePattern
|
||||
: "(" ((SimpleName "=")? pattern{","})? ")"
|
||||
: "(" (((SimpleName "=")? pattern){","})? ")"
|
||||
;
|
||||
|
||||
bindingPattern
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user