Working on bindings in ifs

This commit is contained in:
Andrey Breslav
2011-06-13 14:33:32 +04:00
parent c2aceefe76
commit 3cacb512a3
6 changed files with 128 additions and 48 deletions
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -258,4 +259,19 @@ public class WritableScopeImpl extends WritableScopeWithImports {
if (descriptor != null) return descriptor; if (descriptor != null) return descriptor;
return super.getPropertyByFieldReference(fieldName); return super.getPropertyByFieldReference(fieldName);
} }
public List<VariableDescriptor> getDeclaredVariables() {
List<VariableDescriptor> result = Lists.newArrayList();
for (DeclarationDescriptor descriptor : getVariableClassOrNamespaceDescriptors().values()) {
if (descriptor instanceof VariableDescriptor) {
VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
result.add(variableDescriptor);
}
}
return result;
}
public boolean hasDeclaredItems() {
return variableClassOrNamespaceDescriptors != null && !variableClassOrNamespaceDescriptors.isEmpty();
}
} }
@@ -155,6 +155,7 @@ public class ErrorUtils {
return result; return result;
} }
@NotNull
public static JetType createErrorType(String debugMessage) { public static JetType createErrorType(String debugMessage) {
return createErrorType(debugMessage, ERROR_SCOPE); return createErrorType(debugMessage, ERROR_SCOPE);
} }
@@ -72,6 +72,8 @@ public class JetTypeInferrer {
private final TypeResolver typeResolver; private final TypeResolver typeResolver;
private final ClassDescriptorResolver classDescriptorResolver; private final ClassDescriptorResolver classDescriptorResolver;
private final JetFlowInformationProvider flowInformationProvider; private final JetFlowInformationProvider flowInformationProvider;
private final Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo = Maps.newHashMap();
private final Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists = Maps.newHashMap();
public JetTypeInferrer(@NotNull BindingTrace trace, @NotNull JetFlowInformationProvider flowInformationProvider, @NotNull JetSemanticServices semanticServices) { public JetTypeInferrer(@NotNull BindingTrace trace, @NotNull JetFlowInformationProvider flowInformationProvider, @NotNull JetSemanticServices semanticServices) {
this.trace = trace; //new CachedBindingTrace(trace); this.trace = trace; //new CachedBindingTrace(trace);
@@ -368,8 +370,15 @@ public class JetTypeInferrer {
JetExpression statementExpression = (JetExpression) statement; JetExpression statementExpression = (JetExpression) statement;
result = blockLevelVisitor.getType(statementExpression); result = blockLevelVisitor.getType(statementExpression);
DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo(); DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo();
if (newDataFlowInfo != null) { if (newDataFlowInfo == null) {
blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true, newDataFlowInfo); newDataFlowInfo = dataFlowInfo;
}
WritableScope newScope = blockLevelVisitor.getResultScope();
if (newScope == null) {
newScope = scope;
}
if (newDataFlowInfo != dataFlowInfo || newScope != scope) {
blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(newScope, true, newDataFlowInfo);
} }
else { else {
blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope? blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope?
@@ -582,6 +591,7 @@ public class JetTypeInferrer {
protected JetType result; protected JetType result;
protected DataFlowInfo resultDataFlowInfo; protected DataFlowInfo resultDataFlowInfo;
protected WritableScope resultScope;
private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo) { private TypeInferrerVisitor(@NotNull JetScope scope, boolean preferBlock, @NotNull DataFlowInfo dataFlowInfo) {
this.scope = scope; this.scope = scope;
@@ -594,6 +604,16 @@ public class JetTypeInferrer {
return resultDataFlowInfo; return resultDataFlowInfo;
} }
public WritableScope getResultScope() {
if (resultScope instanceof WritableScopeImpl) {
WritableScopeImpl writableScope = (WritableScopeImpl) resultScope;
if (!writableScope.hasDeclaredItems()) {
return null;
}
}
return resultScope;
}
@Nullable @Nullable
public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, boolean preferBlock) { public JetType getType(@NotNull JetScope scope, @NotNull JetExpression expression, boolean preferBlock) {
return getType(scope, expression, preferBlock, dataFlowInfo); return getType(scope, expression, preferBlock, dataFlowInfo);
@@ -652,6 +672,8 @@ public class JetTypeInferrer {
public void resetResult() { public void resetResult() {
result = null; result = null;
resultDataFlowInfo = null;
resultScope = null;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1096,7 +1118,7 @@ public class JetTypeInferrer {
Set<JetType> expressionTypes = Sets.newHashSet(); Set<JetType> expressionTypes = Sets.newHashSet();
for (JetWhenEntry whenEntry : expression.getEntries()) { for (JetWhenEntry whenEntry : expression.getEntries()) {
JetWhenCondition condition = whenEntry.getCondition(); JetWhenCondition condition = whenEntry.getCondition();
WritableScope scopeToExtend = new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()); WritableScope scopeToExtend = newWritableScopeImpl();
DataFlowInfo newDataFlowInfo = dataFlowInfo; DataFlowInfo newDataFlowInfo = dataFlowInfo;
if (condition != null) { if (condition != null) {
newDataFlowInfo = checkWhenCondition(subjectExpression, subjectType, condition, scopeToExtend, variableDescriptor); newDataFlowInfo = checkWhenCondition(subjectExpression, subjectType, condition, scopeToExtend, variableDescriptor);
@@ -1225,7 +1247,7 @@ public class JetTypeInferrer {
@Override @Override
public void visitExpressionPattern(JetExpressionPattern pattern) { public void visitExpressionPattern(JetExpressionPattern pattern) {
JetType type = getType(scope, pattern.getExpression(), false); JetType type = getType(scopeToExtend, pattern.getExpression(), false);
checkTypeCompatibility(type, subjectType, pattern); checkTypeCompatibility(type, subjectType, pattern);
} }
@@ -1282,7 +1304,7 @@ public class JetTypeInferrer {
if (catchParameter != null) { if (catchParameter != null) {
VariableDescriptor variableDescriptor = classDescriptorResolver.resolveLocalVariableDescriptor(scope.getContainingDeclaration(), scope, catchParameter); VariableDescriptor variableDescriptor = classDescriptorResolver.resolveLocalVariableDescriptor(scope.getContainingDeclaration(), scope, catchParameter);
if (catchBody != null) { if (catchBody != null) {
WritableScope catchScope = new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()); WritableScope catchScope = newWritableScopeImpl();
catchScope.addVariableDescriptor(variableDescriptor); catchScope.addVariableDescriptor(variableDescriptor);
JetType type = getType(catchScope, catchBody, true); JetType type = getType(catchScope, catchBody, true);
if (type != null) { if (type != null) {
@@ -1318,12 +1340,14 @@ public class JetTypeInferrer {
JetExpression elseBranch = expression.getElse(); JetExpression elseBranch = expression.getElse();
JetExpression thenBranch = expression.getThen(); JetExpression thenBranch = expression.getThen();
DataFlowInfo thenInfo = extractDataFlowInfoFromCondition(condition, true); WritableScopeImpl thenScope = newWritableScopeImpl();
DataFlowInfo elseInfo = extractDataFlowInfoFromCondition(condition, false); DataFlowInfo thenInfo = extractDataFlowInfoFromCondition(condition, true, thenScope);
WritableScopeImpl elseScope = newWritableScopeImpl();
DataFlowInfo elseInfo = extractDataFlowInfoFromCondition(condition, false, elseScope);
if (elseBranch == null) { if (elseBranch == null) {
if (thenBranch != null) { if (thenBranch != null) {
JetType type = getType(scope, thenBranch, true, thenInfo); JetType type = getType(thenScope, thenBranch, true, thenInfo);
if (type != null && JetStandardClasses.isNothing(type)) { if (type != null && JetStandardClasses.isNothing(type)) {
resultDataFlowInfo = elseInfo; resultDataFlowInfo = elseInfo;
} }
@@ -1331,15 +1355,15 @@ public class JetTypeInferrer {
} }
} }
else if (thenBranch == null) { else if (thenBranch == null) {
JetType type = getType(scope, elseBranch, true, elseInfo); JetType type = getType(elseScope, elseBranch, true, elseInfo);
if (type != null && JetStandardClasses.isNothing(type)) { if (type != null && JetStandardClasses.isNothing(type)) {
resultDataFlowInfo = thenInfo; resultDataFlowInfo = thenInfo;
} }
result = JetStandardClasses.getUnitType(); result = JetStandardClasses.getUnitType();
} }
else { else {
JetType thenType = getType(scope, thenBranch, true, thenInfo); JetType thenType = getType(thenScope, thenBranch, true, thenInfo);
JetType elseType = getType(scope, elseBranch, true, elseInfo); JetType elseType = getType(elseScope, elseBranch, true, elseInfo);
if (thenType == null) { if (thenType == null) {
result = elseType; result = elseType;
@@ -1364,21 +1388,35 @@ public class JetTypeInferrer {
} }
} }
private DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue) { private DataFlowInfo extractDataFlowInfoFromCondition(@Nullable JetExpression condition, final boolean conditionValue, @NotNull final WritableScope scopeToExtend) {
if (condition == null) return dataFlowInfo; if (condition == null) return dataFlowInfo;
final DataFlowInfo[] result = new DataFlowInfo[] {dataFlowInfo}; final DataFlowInfo[] result = new DataFlowInfo[] {dataFlowInfo};
condition.accept(new JetVisitor() { condition.accept(new JetVisitor() {
@Override @Override
public void visitIsExpression(JetIsExpression expression) { public void visitIsExpression(JetIsExpression expression) {
if (conditionValue) { if (conditionValue) {
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression.getLeftHandSide()); JetPattern pattern = expression.getPattern();
if (variableDescriptor != null) { for (VariableDescriptor variableDescriptor : patternsToBoundVariableLists.get(pattern)) {
JetPattern pattern = expression.getPattern(); scopeToExtend.addVariableDescriptor(variableDescriptor);
if (pattern instanceof JetTypePattern) {
JetTypePattern jetTypePattern = (JetTypePattern) pattern;
result[0] = dataFlowInfo.isInstanceOf(variableDescriptor, trace.getBindingContext().resolveTypeReference(jetTypePattern.getTypeReference()));
}
} }
result[0] = patternsToDataFlowInfo.get(pattern);
// VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression.getLeftHandSide());
// if (variableDescriptor != null && pattern != null) {
// JetType outType = variableDescriptor.getOutType();
// if (outType == null) {
// outType = ErrorUtils.createErrorType("<Unknown>");
// }
// trace.getErrorHandler().openRegion();
// result[0] = checkPatternType(pattern, outType, scopeToExtend, variableDescriptor);
// trace.getErrorHandler().closeAndReturnCurrentRegion();
//
// }
//// if (pattern instanceof JetTypePattern) {
//// JetTypePattern jetTypePattern = (JetTypePattern) pattern;
//// result[0] = dataFlowInfo.isInstanceOf(variableDescriptor, trace.getBindingContext().resolveTypeReference(jetTypePattern.getTypeReference()));
//// }
//// }
} }
} }
@@ -1386,10 +1424,10 @@ public class JetTypeInferrer {
public void visitBinaryExpression(JetBinaryExpression expression) { public void visitBinaryExpression(JetBinaryExpression expression) {
IElementType operationToken = expression.getOperationToken(); IElementType operationToken = expression.getOperationToken();
if (operationToken == JetTokens.ANDAND || operationToken == JetTokens.OROR) { if (operationToken == JetTokens.ANDAND || operationToken == JetTokens.OROR) {
DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue); DataFlowInfo dataFlowInfo = extractDataFlowInfoFromCondition(expression.getLeft(), conditionValue, scopeToExtend); // TODO
JetExpression expressionRight = expression.getRight(); JetExpression expressionRight = expression.getRight();
if (expressionRight != null) { if (expressionRight != null) {
DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue); DataFlowInfo rightInfo = extractDataFlowInfoFromCondition(expressionRight, conditionValue, scopeToExtend); // TODO
DataFlowInfo.CompositionOperator operator; DataFlowInfo.CompositionOperator operator;
if (operationToken == JetTokens.ANDAND) { if (operationToken == JetTokens.ANDAND) {
operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR; operator = conditionValue ? DataFlowInfo.AND : DataFlowInfo.OR;
@@ -1467,7 +1505,7 @@ public class JetTypeInferrer {
if (operationTokenType == JetTokens.EXCL) { if (operationTokenType == JetTokens.EXCL) {
JetExpression baseExpression = expression.getBaseExpression(); JetExpression baseExpression = expression.getBaseExpression();
if (baseExpression != null) { if (baseExpression != null) {
result[0] = extractDataFlowInfoFromCondition(baseExpression, !conditionValue); result[0] = extractDataFlowInfoFromCondition(baseExpression, !conditionValue, scopeToExtend); // TODO
} }
} }
} }
@@ -1499,11 +1537,13 @@ public class JetTypeInferrer {
checkCondition(scope, condition); checkCondition(scope, condition);
JetExpression body = expression.getBody(); JetExpression body = expression.getBody();
if (body != null) { if (body != null) {
DataFlowInfo conditionInfo = condition == null ? dataFlowInfo : extractDataFlowInfoFromCondition(condition, true); WritableScopeImpl scopeToExtend = newWritableScopeImpl();
getType(scope, body, true, conditionInfo); DataFlowInfo conditionInfo = condition == null ? dataFlowInfo : extractDataFlowInfoFromCondition(condition, true, scopeToExtend);
getType(scopeToExtend, body, true, conditionInfo);
} }
if (!flowInformationProvider.isBreakable(expression)) { if (!flowInformationProvider.isBreakable(expression)) {
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false); resultScope = newWritableScopeImpl();
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, resultScope);
} }
result = JetStandardClasses.getUnitType(); result = JetStandardClasses.getUnitType();
} }
@@ -1515,7 +1555,7 @@ public class JetTypeInferrer {
if (body instanceof JetFunctionLiteralExpression) { if (body instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression function = (JetFunctionLiteralExpression) body; JetFunctionLiteralExpression function = (JetFunctionLiteralExpression) body;
if (!function.hasParameterSpecification()) { if (!function.hasParameterSpecification()) {
WritableScope writableScope = new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()); WritableScope writableScope = newWritableScopeImpl();
conditionScope = writableScope; conditionScope = writableScope;
getBlockReturnedTypeWithWritableScope(writableScope, function.getBody(), dataFlowInfo); getBlockReturnedTypeWithWritableScope(writableScope, function.getBody(), dataFlowInfo);
trace.recordBlock(function); trace.recordBlock(function);
@@ -1524,18 +1564,23 @@ public class JetTypeInferrer {
} }
} }
else if (body != null) { else if (body != null) {
WritableScope writableScope = new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()); WritableScope writableScope = newWritableScopeImpl();
conditionScope = writableScope; conditionScope = writableScope;
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo); getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body), dataFlowInfo);
} }
JetExpression condition = expression.getCondition(); JetExpression condition = expression.getCondition();
checkCondition(conditionScope, condition); checkCondition(conditionScope, condition);
if (!flowInformationProvider.isBreakable(expression)) { if (!flowInformationProvider.isBreakable(expression)) {
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false); resultScope = newWritableScopeImpl();
resultDataFlowInfo = extractDataFlowInfoFromCondition(condition, false, resultScope);
} }
result = JetStandardClasses.getUnitType(); result = JetStandardClasses.getUnitType();
} }
protected WritableScopeImpl newWritableScopeImpl() {
return new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler());
}
@Override @Override
public void visitForExpression(JetForExpression expression) { public void visitForExpression(JetForExpression expression) {
JetParameter loopParameter = expression.getLoopParameter(); JetParameter loopParameter = expression.getLoopParameter();
@@ -1549,7 +1594,7 @@ public class JetTypeInferrer {
expectedParameterType = checkIterableConvention(loopRangeType, loopRange.getNode()); expectedParameterType = checkIterableConvention(loopRangeType, loopRange.getNode());
} }
WritableScope loopScope = new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()); WritableScope loopScope = newWritableScopeImpl();
if (loopParameter != null) { if (loopParameter != null) {
JetTypeReference typeReference = loopParameter.getTypeReference(); JetTypeReference typeReference = loopParameter.getTypeReference();
@@ -1733,6 +1778,12 @@ public class JetTypeInferrer {
@Nullable @Nullable
private VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull JetExpression receiverExpression) { private VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull JetExpression receiverExpression) {
if (receiverExpression instanceof JetBinaryExpressionWithTypeRHS) {
JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) receiverExpression;
if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) {
return getVariableDescriptorFromSimpleName(expression.getLeft());
}
}
VariableDescriptor variableDescriptor = null; VariableDescriptor variableDescriptor = null;
if (receiverExpression instanceof JetSimpleNameExpression) { if (receiverExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiverExpression; JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiverExpression;
@@ -1815,27 +1866,14 @@ public class JetTypeInferrer {
@Override @Override
public void visitIsExpression(JetIsExpression expression) { public void visitIsExpression(JetIsExpression expression) {
// TODO : patterns and everything // TODO : patterns and everything
// 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 != null && knownType != null) { if (pattern != null && knownType != null) {
checkPatternType(pattern, knownType, new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler())); WritableScopeImpl scopeToExtend = newWritableScopeImpl();
DataFlowInfo newDataFlowInfo = checkPatternType(pattern, knownType, scopeToExtend, getVariableDescriptorFromSimpleName(expression.getLeftHandSide()));
patternsToDataFlowInfo.put(pattern, newDataFlowInfo);
patternsToBoundVariableLists.put(pattern, scopeToExtend.getDeclaredVariables());
} }
// 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();
} }
@@ -1952,7 +1990,8 @@ public class JetTypeInferrer {
} }
else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) { else if (operationType == JetTokens.ANDAND || operationType == JetTokens.OROR) {
JetType leftType = getType(scope, left, false); JetType leftType = getType(scope, left, false);
DataFlowInfo flowInfoLeft = extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition // TODO!!!
DataFlowInfo flowInfoLeft = extractDataFlowInfoFromCondition(left, operationType == JetTokens.ANDAND, newWritableScopeImpl()); // TODO: This gets computed twice: here and in extractDataFlowInfoFromCondition() for the whole condition
JetType rightType = right == null ? null : getType(scope, right, false, flowInfoLeft); JetType rightType = right == null ? null : getType(scope, right, false, flowInfoLeft);
if (leftType != null && !isBoolean(leftType)) { if (leftType != null && !isBoolean(leftType)) {
trace.getErrorHandler().typeMismatch(left, semanticServices.getStandardLibrary().getBooleanType(), leftType); trace.getErrorHandler().typeMismatch(left, semanticServices.getStandardLibrary().getBooleanType(), leftType);
@@ -2293,6 +2332,14 @@ public class JetTypeInferrer {
trace.getErrorHandler().genericError(element.getNode(), "Unsupported element in a block: " + element + " " + element.getClass().getCanonicalName()); trace.getErrorHandler().genericError(element.getNode(), "Unsupported element in a block: " + element + " " + element.getClass().getCanonicalName());
} }
@NotNull
@Override
public TypeInferrerVisitor createNew(JetScope scope, boolean preferBlock, DataFlowInfo dataFlowInfo) {
// if (scope instanceof WritableScope) {
// return new TypeInferrerVisitorWithWritableScope((WritableScope) scope, preferBlock, dataFlowInfo);
// }
return new TypeInferrerVisitorWithWritableScope(new WritableScopeImpl(scope, scope.getContainingDeclaration(), trace.getErrorHandler()), preferBlock, dataFlowInfo);
}
} }
// private class CachedBindingTrace extends BindingTraceAdapter { // private class CachedBindingTrace extends BindingTraceAdapter {
+1 -1
View File
@@ -1,6 +1,6 @@
fun test() { fun test() {
if (1 is Int) { if (1 is Int) {
if (<warning>1 is Boolean</warning>) { if (1 is <error>Boolean</error>) {
} }
} }
+10
View File
@@ -75,4 +75,14 @@ fun f12(a : A?) {
is val c is C => <info descr="Automatically cast to C">a</info>.bar() is val c is C => <info descr="Automatically cast to C">a</info>.bar()
else => a?.foo() else => a?.foo()
} }
if (a is val b) {
a?.<error>bar</error>()
b?.foo()
}
if (a is val b is B) {
b.foo()
<info descr="Automatically cast to B">a</info>.bar()
<info descr="Automatically cast to B">b</info>.bar()
}
} }
@@ -0,0 +1,6 @@
fun test() {
val a : Any? = null
if (a is Any) else a = null;
while (a is Any) a = null
while (true) a = null
}