Working on bindings
This commit is contained in:
@@ -80,12 +80,34 @@ public class DataFlowInfo {
|
|||||||
return ImmutableMap.copyOf(builder);
|
return ImmutableMap.copyOf(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ImmutableMap<VariableDescriptor, NullabilityFlags> getEqualsToNullMap(VariableDescriptor[] variableDescriptors, boolean notNull) {
|
||||||
|
if (variableDescriptors.length == 0) return nullabilityInfo;
|
||||||
|
Map<VariableDescriptor, NullabilityFlags> builder = Maps.newHashMap(nullabilityInfo);
|
||||||
|
for (VariableDescriptor variableDescriptor : variableDescriptors) {
|
||||||
|
if (variableDescriptor != null) {
|
||||||
|
builder.put(variableDescriptor, new NullabilityFlags(!notNull, notNull));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ImmutableMap.copyOf(builder);
|
||||||
|
}
|
||||||
|
|
||||||
public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor variableDescriptor, @NotNull JetType type) {
|
public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor variableDescriptor, @NotNull JetType type) {
|
||||||
ListMultimap<VariableDescriptor, JetType> newTypeInfo = copyTypeInfo();
|
ListMultimap<VariableDescriptor, JetType> newTypeInfo = copyTypeInfo();
|
||||||
newTypeInfo.put(variableDescriptor, type);
|
newTypeInfo.put(variableDescriptor, type);
|
||||||
return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, !type.isNullable()), newTypeInfo);
|
return new DataFlowInfo(getEqualsToNullMap(variableDescriptor, !type.isNullable()), newTypeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DataFlowInfo isInstanceOf(@NotNull VariableDescriptor[] variableDescriptors, @NotNull JetType type) {
|
||||||
|
if (variableDescriptors.length == 0) return this;
|
||||||
|
ListMultimap<VariableDescriptor, JetType> newTypeInfo = copyTypeInfo();
|
||||||
|
for (VariableDescriptor variableDescriptor : variableDescriptors) {
|
||||||
|
if (variableDescriptor != null) {
|
||||||
|
newTypeInfo.put(variableDescriptor, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new DataFlowInfo(getEqualsToNullMap(variableDescriptors, !type.isNullable()), newTypeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
public DataFlowInfo and(DataFlowInfo other) {
|
public DataFlowInfo and(DataFlowInfo other) {
|
||||||
Map<VariableDescriptor, NullabilityFlags> nullabilityMapBuilder = Maps.newHashMap();
|
Map<VariableDescriptor, NullabilityFlags> nullabilityMapBuilder = Maps.newHashMap();
|
||||||
nullabilityMapBuilder.putAll(nullabilityInfo);
|
nullabilityMapBuilder.putAll(nullabilityInfo);
|
||||||
|
|||||||
@@ -1099,7 +1099,7 @@ public class JetTypeInferrer {
|
|||||||
WritableScope scopeToExtend = new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler());
|
WritableScope scopeToExtend = new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler());
|
||||||
DataFlowInfo newDataFlowInfo = dataFlowInfo;
|
DataFlowInfo newDataFlowInfo = dataFlowInfo;
|
||||||
if (condition != null) {
|
if (condition != null) {
|
||||||
newDataFlowInfo = checkWhenCondition(subjectExpression, subjectType, variableDescriptor, condition, scopeToExtend);
|
newDataFlowInfo = checkWhenCondition(subjectExpression, subjectType, condition, scopeToExtend, variableDescriptor);
|
||||||
}
|
}
|
||||||
JetWhenExpression subWhen = whenEntry.getSubWhen();
|
JetWhenExpression subWhen = whenEntry.getSubWhen();
|
||||||
JetExpression bodyExpression = subWhen == null ? whenEntry.getExpression() : subWhen;
|
JetExpression bodyExpression = subWhen == null ? whenEntry.getExpression() : subWhen;
|
||||||
@@ -1119,7 +1119,7 @@ public class JetTypeInferrer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataFlowInfo checkWhenCondition(@Nullable final JetExpression subjectExpression, final JetType subjectType, final VariableDescriptor variableDescriptor, JetWhenCondition condition, final WritableScope scopeToExtend) {
|
private DataFlowInfo checkWhenCondition(@Nullable final JetExpression subjectExpression, final JetType subjectType, JetWhenCondition condition, final WritableScope scopeToExtend, final VariableDescriptor... subjectVariables) {
|
||||||
final DataFlowInfo[] newDataFlowInfo = new DataFlowInfo[]{dataFlowInfo};
|
final DataFlowInfo[] newDataFlowInfo = new DataFlowInfo[]{dataFlowInfo};
|
||||||
condition.accept(new JetVisitor() {
|
condition.accept(new JetVisitor() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1159,7 +1159,7 @@ public class JetTypeInferrer {
|
|||||||
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
||||||
JetPattern pattern = condition.getPattern();
|
JetPattern pattern = condition.getPattern();
|
||||||
if (pattern != null) {
|
if (pattern != null) {
|
||||||
newDataFlowInfo[0] = checkPatternType(variableDescriptor, pattern, subjectType, scopeToExtend);
|
newDataFlowInfo[0] = checkPatternType(pattern, subjectType, scopeToExtend, subjectVariables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1171,7 +1171,7 @@ public class JetTypeInferrer {
|
|||||||
return newDataFlowInfo[0];
|
return newDataFlowInfo[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataFlowInfo checkPatternType(@Nullable final VariableDescriptor subjectVariable, @NotNull JetPattern pattern, @NotNull final JetType subjectType, @NotNull final WritableScope scopeToExtend) {
|
private DataFlowInfo checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType, @NotNull final WritableScope scopeToExtend, @NotNull final VariableDescriptor... subjectVariables) {
|
||||||
final DataFlowInfo[] result = new DataFlowInfo[] {dataFlowInfo};
|
final DataFlowInfo[] result = new DataFlowInfo[] {dataFlowInfo};
|
||||||
pattern.accept(new JetVisitor() {
|
pattern.accept(new JetVisitor() {
|
||||||
@Override
|
@Override
|
||||||
@@ -1180,9 +1180,7 @@ public class JetTypeInferrer {
|
|||||||
if (typeReference != null) {
|
if (typeReference != null) {
|
||||||
JetType type = typeResolver.resolveType(scope, typeReference);
|
JetType type = typeResolver.resolveType(scope, typeReference);
|
||||||
checkTypeCompatibility(type, subjectType, typePattern);
|
checkTypeCompatibility(type, subjectType, typePattern);
|
||||||
if (subjectVariable != null) {
|
result[0] = dataFlowInfo.isInstanceOf(subjectVariables, type);
|
||||||
result[0] = dataFlowInfo.isInstanceOf(subjectVariable, type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1207,7 +1205,7 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
JetPattern entryPattern = entry.getPattern();
|
JetPattern entryPattern = entry.getPattern();
|
||||||
if (entryPattern != null) {
|
if (entryPattern != null) {
|
||||||
result[0] = checkPatternType(null, entryPattern, type, scopeToExtend);
|
result[0] = checkPatternType(entryPattern, type, scopeToExtend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1217,7 +1215,7 @@ public class JetTypeInferrer {
|
|||||||
public void visitDecomposerPattern(JetDecomposerPattern pattern) {
|
public void visitDecomposerPattern(JetDecomposerPattern pattern) {
|
||||||
JetType selectorReturnType = getSelectorReturnType(subjectType, pattern.getDecomposerExpression());
|
JetType selectorReturnType = getSelectorReturnType(subjectType, pattern.getDecomposerExpression());
|
||||||
|
|
||||||
result[0] = checkPatternType(null, pattern.getArgumentList(), selectorReturnType == null ? ErrorUtils.createErrorType("No type") : selectorReturnType, scopeToExtend);
|
result[0] = checkPatternType(pattern.getArgumentList(), selectorReturnType == null ? ErrorUtils.createErrorType("No type") : selectorReturnType, scopeToExtend);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1246,7 +1244,11 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
JetWhenCondition condition = pattern.getCondition();
|
JetWhenCondition condition = pattern.getCondition();
|
||||||
if (condition != null) {
|
if (condition != null) {
|
||||||
result[0] = checkWhenCondition(null, subjectType, variableDescriptor, condition, scopeToExtend);
|
int oldLength = subjectVariables.length;
|
||||||
|
VariableDescriptor[] newSubjectVariables = new VariableDescriptor[oldLength + 1];
|
||||||
|
System.arraycopy(subjectVariables, 0, newSubjectVariables, 0, oldLength);
|
||||||
|
newSubjectVariables[oldLength] = variableDescriptor;
|
||||||
|
result[0] = checkWhenCondition(null, subjectType, condition, scopeToExtend, newSubjectVariables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1816,21 +1818,24 @@ public class JetTypeInferrer {
|
|||||||
// TODO : Unify with WhenExpression
|
// TODO : Unify with WhenExpression
|
||||||
JetType knownType = getType(scope, expression.getLeftHandSide(), false);
|
JetType knownType = getType(scope, expression.getLeftHandSide(), false);
|
||||||
JetPattern pattern = expression.getPattern();
|
JetPattern pattern = expression.getPattern();
|
||||||
if (pattern instanceof JetTypePattern) {
|
if (pattern != null && knownType != null) {
|
||||||
JetTypePattern typePattern = (JetTypePattern) pattern;
|
checkPatternType(pattern, knownType, new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()));
|
||||||
JetTypeReference typeReference = typePattern.getTypeReference();
|
|
||||||
if (typeReference != null && knownType != null) {
|
|
||||||
JetType targetType = typeResolver.resolveType(scope, typeReference);
|
|
||||||
if (!semanticServices.getTypeChecker().isSubtypeOf(targetType, knownType)) {
|
|
||||||
trace.getErrorHandler().genericWarning(expression.getNode(), "Expression always evaluates to false"); // TODO : make an error?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (pattern != null) {
|
|
||||||
trace.getErrorHandler().genericError(pattern.getNode(), "Unsupported [JetTypeInferrer]");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// if (pattern instanceof JetTypePattern) {
|
||||||
|
// JetTypePattern typePattern = (JetTypePattern) pattern;
|
||||||
|
// JetTypeReference typeReference = typePattern.getTypeReference();
|
||||||
|
// if (typeReference != null && knownType != null) {
|
||||||
|
// JetType targetType = typeResolver.resolveType(scope, typeReference);
|
||||||
|
// if (!semanticServices.getTypeChecker().isSubtypeOf(targetType, knownType)) {
|
||||||
|
// trace.getErrorHandler().genericWarning(expression.getNode(), "Expression always evaluates to false"); // TODO : make an error?
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// if (pattern != null) {
|
||||||
|
// trace.getErrorHandler().genericError(pattern.getNode(), "Unsupported [JetTypeInferrer]");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
result = semanticServices.getStandardLibrary().getBooleanType();
|
result = semanticServices.getStandardLibrary().getBooleanType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ fun f12(a : A?) {
|
|||||||
is Any => a.foo();
|
is Any => a.foo();
|
||||||
is Any? => a.<error>bar</error>()
|
is Any? => a.<error>bar</error>()
|
||||||
is val c : <error>B</error> => c.foo()
|
is val c : <error>B</error> => c.foo()
|
||||||
is val c is C => c.foo()
|
is val c is C => <info descr="Automatically cast to C">c</info>.bar()
|
||||||
|
is val c is C => <info descr="Automatically cast to C">a</info>.bar()
|
||||||
else => a?.foo()
|
else => a?.foo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user