Migrating BindingTraceContext to a transactional form
This commit is contained in:
@@ -119,7 +119,7 @@ parameter
|
|||||||
;
|
;
|
||||||
|
|
||||||
object
|
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]
|
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
|
// 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))
|
// to put a tuple, write write ((e))
|
||||||
tupleLiteral
|
tupleLiteral
|
||||||
: "(" ((SimpleName "=")? expression){","} ")"
|
: "(" (((SimpleName "=")? expression){","})? ")"
|
||||||
;
|
;
|
||||||
|
|
||||||
// one can use "it" as a parameter name
|
// one can use "it" as a parameter name
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ constantPattern
|
|||||||
;
|
;
|
||||||
|
|
||||||
tuplePattern
|
tuplePattern
|
||||||
: "(" ((SimpleName "=")? pattern{","})? ")"
|
: "(" (((SimpleName "=")? pattern){","})? ")"
|
||||||
;
|
;
|
||||||
|
|
||||||
bindingPattern
|
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 dbl : Double
|
||||||
abstract val flt : Float
|
abstract val flt : Float
|
||||||
abstract val lng : Long
|
abstract val lng : Long
|
||||||
|
|||||||
@@ -50,11 +50,6 @@ public class JetSemanticServices {
|
|||||||
return new JetTypeInferrer(flowInformationProvider, this).getServices(trace);
|
return new JetTypeInferrer(flowInformationProvider, this).getServices(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @NotNull
|
|
||||||
// public ErrorHandler getErrorHandler() {
|
|
||||||
// return errorHandler;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetTypeChecker getTypeChecker() {
|
public JetTypeChecker getTypeChecker() {
|
||||||
return typeChecker;
|
return typeChecker;
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ public class JetAnnotationEntry extends JetElement implements JetCall {
|
|||||||
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
|
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetExpression getCalleeExpression() {
|
||||||
|
// Make callee an expression instead of a type reference
|
||||||
|
throw new UnsupportedOperationException(); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetValueArgumentList getValueArgumentList() {
|
public JetValueArgumentList getValueArgumentList() {
|
||||||
return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import java.util.List;
|
|||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public interface JetCall extends PsiElement {
|
public interface JetCall extends PsiElement {
|
||||||
|
@Nullable
|
||||||
|
JetExpression getCalleeExpression();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
JetValueArgumentList getValueArgumentList();
|
JetValueArgumentList getValueArgumentList();
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class JetCallExpression extends JetExpression implements JetCall {
|
|||||||
return visitor.visitCallExpression(this, data);
|
return visitor.visitCallExpression(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public JetExpression getCalleeExpression() {
|
public JetExpression getCalleeExpression() {
|
||||||
return findChildByClass(JetExpression.class);
|
return findChildByClass(JetExpression.class);
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements J
|
|||||||
return visitor.visitDelegationToSuperCallSpecifier(this, data);
|
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
|
@Nullable
|
||||||
public JetValueArgumentList getValueArgumentList() {
|
public JetValueArgumentList getValueArgumentList() {
|
||||||
return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier implements Je
|
|||||||
return visitor.visitDelegationToThisCall(this, data);
|
return visitor.visitDelegationToThisCall(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JetExpression getCalleeExpression() {
|
||||||
|
return getThisReference();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public JetValueArgumentList getValueArgumentList() {
|
public JetValueArgumentList getValueArgumentList() {
|
||||||
return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
return (JetValueArgumentList) findChildByType(JetNodeTypes.VALUE_ARGUMENT_LIST);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class AnalyzingUtils {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
||||||
bindingTraceContext.getErrorHandler().genericError(file.getNode(), e.getClass().getSimpleName() + ": " + e.getMessage());
|
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");
|
throw new IllegalStateException("Must be guaranteed not to happen by the parser");
|
||||||
}
|
}
|
||||||
}, Collections.<JetDeclaration>singletonList(namespace));
|
}, Collections.<JetDeclaration>singletonList(namespace));
|
||||||
return bindingTraceContext;
|
return bindingTraceContext.getBindingContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void applyHandler(@NotNull ErrorHandler errorHandler, @NotNull BindingContext bindingContext) {
|
public static void applyHandler(@NotNull ErrorHandler errorHandler, @NotNull BindingContext bindingContext) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import java.util.*;
|
|||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @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<JetExpression, JetType> expressionTypes = new HashMap<JetExpression, JetType>();
|
||||||
private final Map<JetReferenceExpression, DeclarationDescriptor> resolutionResults = new HashMap<JetReferenceExpression, DeclarationDescriptor>();
|
private final Map<JetReferenceExpression, DeclarationDescriptor> resolutionResults = new HashMap<JetReferenceExpression, DeclarationDescriptor>();
|
||||||
private final Map<JetReferenceExpression, PsiElement> labelResolutionResults = new HashMap<JetReferenceExpression, PsiElement>();
|
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<JetAnnotationEntry, AnnotationDescriptor> annotationDescriptos = Maps.newHashMap();
|
||||||
private Map<JetExpression, CompileTimeConstant<?>> compileTimeValues = 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() {
|
public BindingTraceContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +235,11 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
diagnostics.addAll(other.diagnostics);
|
diagnostics.addAll(other.diagnostics);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BindingContext getBindingContext() {
|
||||||
|
return bindingContext;
|
||||||
|
}
|
||||||
|
|
||||||
private <K, V> void safePutAll(Map<K, V> my, Map<K, V> other) {
|
private <K, V> void safePutAll(Map<K, V> my, Map<K, V> other) {
|
||||||
assert keySetIntersection(my, other).isEmpty() : keySetIntersection(my, other);
|
assert keySetIntersection(my, other).isEmpty() : keySetIntersection(my, other);
|
||||||
|
|
||||||
@@ -84,7 +252,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
return keySet;
|
return keySet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -196,97 +363,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
statements.remove(statement);
|
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) {
|
private DeclarationDescriptor getOriginal(DeclarationDescriptor declarationDescriptor) {
|
||||||
if (declarationDescriptor instanceof VariableAsFunctionDescriptor) {
|
if (declarationDescriptor instanceof VariableAsFunctionDescriptor) {
|
||||||
VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) declarationDescriptor;
|
VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) declarationDescriptor;
|
||||||
@@ -295,78 +371,6 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
return declarationDescriptor.getOriginal();
|
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
|
@Override
|
||||||
public void markAsProcessed(@NotNull JetExpression expression) {
|
public void markAsProcessed(@NotNull JetExpression expression) {
|
||||||
processed.add(expression);
|
processed.add(expression);
|
||||||
@@ -377,8 +381,4 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
return processed.contains(expression);
|
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.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);
|
trace.recordDeclarationResolution(classElement, descriptor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class ScopeWithReceiver extends JetScopeImpl {
|
|||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
// // TODO : in case of inferred type arguments, substitute the receiver type first
|
// // 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<JetNamedFunction, FunctionDescriptorImpl> functions = Maps.newLinkedHashMap();
|
||||||
private final Map<JetDeclaration, ConstructorDescriptor> constructors = 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 Map<JetDeclaration, JetScope> declaringScopes = Maps.newHashMap();
|
||||||
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet();
|
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>();
|
// private static final Map<Project, JetStandardLibrary> standardLibraryCache = new HashMap<Project, JetStandardLibrary>();
|
||||||
|
|
||||||
// TODO : double checked locking
|
// TODO : double checked locking
|
||||||
synchronized public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) {
|
synchronized
|
||||||
|
public static JetStandardLibrary getJetStandardLibrary(@NotNull Project project) {
|
||||||
if (cachedLibrary == null) {
|
if (cachedLibrary == null) {
|
||||||
cachedLibrary = new JetStandardLibrary(project);
|
cachedLibrary = new JetStandardLibrary(project);
|
||||||
}
|
}
|
||||||
@@ -55,8 +56,8 @@ public class JetStandardLibrary {
|
|||||||
private final ClassDescriptor arrayClass;
|
private final ClassDescriptor arrayClass;
|
||||||
private final ClassDescriptor iterableClass;
|
private final ClassDescriptor iterableClass;
|
||||||
private final ClassDescriptor typeInfoClass;
|
private final ClassDescriptor typeInfoClass;
|
||||||
private final JetType byteType;
|
|
||||||
|
|
||||||
|
private final JetType byteType;
|
||||||
private final JetType charType;
|
private final JetType charType;
|
||||||
private final JetType shortType;
|
private final JetType shortType;
|
||||||
private final JetType intType;
|
private final JetType intType;
|
||||||
@@ -86,7 +87,7 @@ public class JetStandardLibrary {
|
|||||||
// bootstrappingTDA.process(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace().getDeclarations());
|
// bootstrappingTDA.process(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace().getDeclarations());
|
||||||
bootstrappingTDA.processStandardLibraryNamespace(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace());
|
bootstrappingTDA.processStandardLibraryNamespace(writableScope, JetStandardClasses.STANDARD_CLASSES_NAMESPACE, file.getRootNamespace());
|
||||||
this.libraryScope = JetStandardClasses.STANDARD_CLASSES_NAMESPACE.getMemberScope();
|
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.byteClass = (ClassDescriptor) libraryScope.getClassifier("Byte");
|
||||||
this.charClass = (ClassDescriptor) libraryScope.getClassifier("Char");
|
this.charClass = (ClassDescriptor) libraryScope.getClassifier("Char");
|
||||||
|
|||||||
@@ -313,28 +313,10 @@ public class JetTypeChecker {
|
|||||||
return false;
|
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
|
// 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
|
// as the second parameter, applying the substitution of type arguments to it
|
||||||
@Nullable
|
@Nullable
|
||||||
private JetType findCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
private static JetType findCorrespondingSupertype(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
TypeConstructor constructor = subtype.getConstructor();
|
TypeConstructor constructor = subtype.getConstructor();
|
||||||
if (constructor.equals(supertype.getConstructor())) {
|
if (constructor.equals(supertype.getConstructor())) {
|
||||||
return subtype;
|
return subtype;
|
||||||
@@ -348,75 +330,270 @@ public class JetTypeChecker {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) {
|
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
TypeConstructor constructor = subtype.getConstructor();
|
return new TypeCheckingProcedure().run(subtype, supertype);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.CompileTimeConstant;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.ErrorValue;
|
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.lexer.JetTokens;
|
||||||
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
import org.jetbrains.jet.lang.resolve.constants.StringValue;
|
||||||
@@ -533,6 +534,71 @@ public class JetTypeInferrer {
|
|||||||
return result;
|
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
|
@Nullable
|
||||||
private JetType resolveCall(
|
private JetType resolveCall(
|
||||||
@NotNull JetScope scope,
|
@NotNull JetScope scope,
|
||||||
@@ -2230,6 +2296,7 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) {
|
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);
|
return context.services.checkType(getCallExpressionType(null, expression, context), expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,30 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class TypeSubstitutor {
|
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 TypeSubstitutor EMPTY = create(Collections.<TypeConstructor, TypeProjection>emptyMap());
|
||||||
|
|
||||||
public static final class SubstitutionException extends Exception {
|
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) {
|
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) {
|
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;
|
this.substitutionContext = substitutionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +137,7 @@ public class TypeSubstitutor {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private TypeProjection substituteInProjection(
|
private TypeProjection substituteInProjection(
|
||||||
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
|
@NotNull TypeSubstitution substitutionContext,
|
||||||
@NotNull TypeProjection passedProjection,
|
@NotNull TypeProjection passedProjection,
|
||||||
@NotNull TypeParameterDescriptor correspondingTypeParameter,
|
@NotNull TypeParameterDescriptor correspondingTypeParameter,
|
||||||
@NotNull Variance contextCallSiteVariance) throws SubstitutionException {
|
@NotNull Variance contextCallSiteVariance) throws SubstitutionException {
|
||||||
@@ -181,10 +209,6 @@ public class TypeSubstitutor {
|
|||||||
return new TypeProjection(effectiveProjectionKindValue, specializeType(effectiveTypeValue, effectiveContextVariance));
|
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) {
|
private static Variance asymmetricOr(Variance a, Variance b) {
|
||||||
return a == Variance.INVARIANT ? b : a;
|
return a == Variance.INVARIANT ? b : a;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ public class TypeUtils {
|
|||||||
|
|
||||||
StringBuilder debugName = new StringBuilder();
|
StringBuilder debugName = new StringBuilder();
|
||||||
boolean nullable = false;
|
boolean nullable = false;
|
||||||
|
Set<JetType> resultingTypes = Sets.newHashSet();
|
||||||
|
|
||||||
|
outer:
|
||||||
for (Iterator<JetType> iterator = types.iterator(); iterator.hasNext();) {
|
for (Iterator<JetType> iterator = types.iterator(); iterator.hasNext();) {
|
||||||
JetType type = iterator.next();
|
JetType type = iterator.next();
|
||||||
|
|
||||||
@@ -63,9 +66,17 @@ public class TypeUtils {
|
|||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
for (JetType other : types) {
|
||||||
|
if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) {
|
||||||
|
continue outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nullable |= type.isNullable();
|
nullable |= type.isNullable();
|
||||||
|
|
||||||
|
resultingTypes.add(type);
|
||||||
debugName.append(type.toString());
|
debugName.append(type.toString());
|
||||||
if (iterator.hasNext()) {
|
if (iterator.hasNext()) {
|
||||||
debugName.append(" & ");
|
debugName.append(" & ");
|
||||||
@@ -79,11 +90,11 @@ public class TypeUtils {
|
|||||||
false,
|
false,
|
||||||
debugName.toString(),
|
debugName.toString(),
|
||||||
Collections.<TypeParameterDescriptor>emptyList(),
|
Collections.<TypeParameterDescriptor>emptyList(),
|
||||||
types);
|
resultingTypes);
|
||||||
|
|
||||||
JetScope[] scopes = new JetScope[types.size()];
|
JetScope[] scopes = new JetScope[resultingTypes.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (JetType type : types) {
|
for (JetType type : resultingTypes) {
|
||||||
scopes[i] = type.getMemberScope();
|
scopes[i] = type.getMemberScope();
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -217,12 +228,15 @@ public class TypeUtils {
|
|||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static TypeSubstitutor buildDeepSubstitutor(@NotNull JetType type) {
|
public static TypeSubstitutor buildDeepSubstitutor(@NotNull JetType type) {
|
||||||
TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(Maps.<TypeConstructor, TypeProjection>newHashMap());
|
HashMap<TypeConstructor, TypeProjection> substitution = Maps.<TypeConstructor, TypeProjection>newHashMap();
|
||||||
fillInDeepSubstitutor(type, typeSubstitutor);
|
TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitution);
|
||||||
|
// we use the mutability of the map here
|
||||||
|
fillInDeepSubstitutor(type, typeSubstitutor, substitution);
|
||||||
return typeSubstitutor;
|
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<TypeParameterDescriptor> parameters = context.getConstructor().getParameters();
|
||||||
List<TypeProjection> arguments = context.getArguments();
|
List<TypeProjection> arguments = context.getArguments();
|
||||||
for (int i = 0; i < arguments.size(); i++) {
|
for (int i = 0; i < arguments.size(); i++) {
|
||||||
@@ -232,10 +246,10 @@ public class TypeUtils {
|
|||||||
JetType substitute = substitutor.substitute(argument.getType(), Variance.INVARIANT);
|
JetType substitute = substitutor.substitute(argument.getType(), Variance.INVARIANT);
|
||||||
assert substitute != null;
|
assert substitute != null;
|
||||||
TypeProjection substitutedTypeProjection = new TypeProjection(argument.getProjectionKind(), substitute);
|
TypeProjection substitutedTypeProjection = new TypeProjection(argument.getProjectionKind(), substitute);
|
||||||
substitutor.addSubstitution(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection);
|
substitution.put(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection);
|
||||||
}
|
}
|
||||||
for (JetType supertype : context.getConstructor().getSupertypes()) {
|
for (JetType supertype : context.getConstructor().getSupertypes()) {
|
||||||
fillInDeepSubstitutor(supertype, substitutor);
|
fillInDeepSubstitutor(supertype, substitutor, substitution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,18 @@ public enum Variance {
|
|||||||
throw new IllegalStateException();
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return label;
|
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