From 525b9e63aed035987e0fd5401a3ba519a8c7102a Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 23 Apr 2015 14:00:08 +0300 Subject: [PATCH] Refactoring: checkType && checkImplicitCast returned to DataFlowUtils, PROCESSED unboxing returned, StringTemplateVisitor made local --- .../kotlin/resolve/BindingContextUtils.java | 3 +- .../BasicExpressionTypingVisitor.java | 75 +++++++++---------- .../ControlStructureTypingVisitor.java | 25 +++++-- .../types/expressions/DataFlowUtils.java | 10 +++ .../ExpressionTypingVisitorForStatements.java | 2 +- .../kotlin/types/expressions/JetTypeInfo.kt | 20 ++--- .../PatternMatchingTypingVisitor.java | 2 +- .../types/expressions/TypeInfoFactory.kt | 3 +- .../loops/ifBreakAssignInsideDoWhile.kt | 4 +- 9 files changed, 78 insertions(+), 66 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java index 3b4850f6bb9..d94b08ef6ac 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java @@ -157,8 +157,9 @@ public class BindingContextUtils { @Nullable public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) { + // noinspection ConstantConditions + if (!context.get(BindingContext.PROCESSED, expression)) return null; // NB: should never return null if expression is already processed - if (!Boolean.TRUE.equals(context.get(BindingContext.PROCESSED, expression))) return null; JetTypeInfo result = context.get(BindingContext.EXPRESSION_TYPE_INFO, expression); return result != null ? result : TypeInfoFactoryPackage.noTypeInfo(DataFlowInfo.EMPTY); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index ccbf06ea810..45d99db133d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -104,7 +104,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { // TODO : type substitutions??? CallExpressionResolver callExpressionResolver = components.expressionTypingServices.getCallExpressionResolver(); JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context); - return typeInfo.checkType(expression, context); // TODO : Extensions to this + return DataFlowUtils.checkType(typeInfo, expression, context); // TODO : Extensions to this } @Override @@ -158,7 +158,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType.replaceExpectedType(targetType)); checkBinaryWithTypeRHS(expression, context, targetType, typeInfo.getType()); - return typeInfo.replaceType(targetType).checkType(expression, context); + return DataFlowUtils.checkType(typeInfo.replaceType(targetType), expression, context); } JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType); @@ -176,7 +176,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } JetType result = operationType == AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType; - return typeInfo.replaceType(result).checkType(expression, context); + return DataFlowUtils.checkType(typeInfo.replaceType(result), expression, context); } private void checkBinaryWithTypeRHS( @@ -582,7 +582,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } }); result[0] = defaultType; - if (Boolean.FALSE.equals(context.trace.get(PROCESSED, expression))) { + // noinspection ConstantConditions + if (!context.trace.get(PROCESSED, expression)) { temporaryTrace.recordType(expression, defaultType); temporaryTrace.record(PROCESSED, expression); } @@ -887,7 +888,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType); } - return typeInfo.replaceType(result).checkType(expression, contextWithExpectedType); + return DataFlowUtils.checkType(typeInfo.replaceType(result), expression, contextWithExpectedType); } @NotNull @@ -936,7 +937,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } // The call to checkType() is only needed here to execute additionalTypeCheckers, hence the NO_EXPECTED_TYPE - return baseTypeInfo.replaceType(resultingType).checkType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE)); + return DataFlowUtils.checkType(baseTypeInfo.replaceType(resultingType), expression, context.replaceExpectedType(NO_EXPECTED_TYPE)); } @Override @@ -1087,7 +1088,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (value != null) { return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType); } - return result.checkType(expression, contextWithExpectedType); + return DataFlowUtils.checkType(result, expression, contextWithExpectedType); } private JetTypeInfo visitEquality( @@ -1357,7 +1358,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, ExpressionTypingContext context) { - return resolveArrayAccessGetMethod(expression, context).checkType(expression, context); + return DataFlowUtils.checkType(resolveArrayAccessGetMethod(expression, context), expression, context); } @NotNull @@ -1409,45 +1410,37 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return TypeInfoFactoryPackage.noTypeInfo(context); } - private class StringTemplateVisitor extends JetVisitorVoid { - - final ExpressionTypingContext context; - - JetTypeInfo typeInfo; - - StringTemplateVisitor(ExpressionTypingContext context) { - this.context = context; - this.typeInfo = TypeInfoFactoryPackage.noTypeInfo(context); - } - - @Override - public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) { - JetExpression entryExpression = entry.getExpression(); - if (entryExpression != null) { - typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(typeInfo.getDataFlowInfo())); - } - } - - @Override - public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) { - CompileTimeConstantChecker.CharacterWithDiagnostic value = CompileTimeConstantChecker.escapedStringToCharacter(entry.getText(), entry); - Diagnostic diagnostic = value.getDiagnostic(); - if (diagnostic != null) { - context.trace.report(diagnostic); - } - } - - } - @Override public JetTypeInfo visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression, ExpressionTypingContext contextWithExpectedType) { - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); - StringTemplateVisitor visitor = new StringTemplateVisitor(context); + final ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); + class StringTemplateVisitor extends JetVisitorVoid { + private JetTypeInfo typeInfo = TypeInfoFactoryPackage.noTypeInfo(context); + + @Override + public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) { + JetExpression entryExpression = entry.getExpression(); + if (entryExpression != null) { + typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(typeInfo.getDataFlowInfo())); + } + } + + @Override + public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) { + CompileTimeConstantChecker.CharacterWithDiagnostic value = CompileTimeConstantChecker.escapedStringToCharacter(entry.getText(), entry); + Diagnostic diagnostic = value.getDiagnostic(); + if (diagnostic != null) { + context.trace.report(diagnostic); + } + } + } + StringTemplateVisitor visitor = new StringTemplateVisitor(); for (JetStringTemplateEntry entry : expression.getEntries()) { entry.accept(visitor); } ConstantExpressionEvaluator.evaluate(expression, context.trace, contextWithExpectedType.expectedType); - return visitor.typeInfo.replaceType(components.builtIns.getStringType()).checkType(expression, contextWithExpectedType); + return DataFlowUtils.checkType(visitor.typeInfo.replaceType(components.builtIns.getStringType()), + expression, + contextWithExpectedType); } @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index dd716479d3b..66dd6af69f6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -189,8 +189,12 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } else { dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo); } - return typeInfo.replaceType(components.builtIns.getUnitType()).checkType(ifExpression, context). - checkImplicitCast(ifExpression, context, isStatement).replaceDataFlowInfo(dataFlowInfo); + return DataFlowUtils.checkImplicitCast(DataFlowUtils.checkType(typeInfo.replaceType(components.builtIns.getUnitType()), + ifExpression, + context), + ifExpression, + context, + isStatement).replaceDataFlowInfo(dataFlowInfo); } @Override @@ -240,8 +244,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { // but without affecting changing variables dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo())); } - return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo( - dataFlowInfo); + return DataFlowUtils + .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) + .replaceDataFlowInfo(dataFlowInfo); } private boolean containsJumpOutOfLoop(final JetLoopExpression loopExpression, final ExpressionTypingContext context) { @@ -337,13 +342,16 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { // Here we must record data flow information at the end of the body (or at the first jump, to be precise) and // .and it with entrance data flow information, because do-while body is executed at least once // See KT-6283 + // NB: it's really important to do it for non-empty body which is not a function literal + // If it's a function literal, it appears always unused so it's no matter what we do at this point if (body != null) { // We should take data flow info from the first jump point, // but without affecting changing variables dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo())); } - return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo( - dataFlowInfo); + return DataFlowUtils + .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) + .replaceDataFlowInfo(dataFlowInfo); } @Override @@ -402,8 +410,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { bodyTypeInfo = loopRangeInfo; } - return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo( - loopRangeInfo.getDataFlowInfo()); + return DataFlowUtils + .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) + .replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo()); } private VariableDescriptor createLoopParameterDescriptor( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowUtils.java index 1fdb4673068..6365cca816e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowUtils.java @@ -149,6 +149,11 @@ public class DataFlowUtils { return checkType(expressionType, expression, context, null); } + @NotNull + public static JetTypeInfo checkType(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context) { + return typeInfo.replaceType(checkType(typeInfo.getType(), expression, context)); + } + @Nullable public static JetType checkType( @Nullable JetType expressionType, @@ -220,6 +225,11 @@ public class DataFlowUtils { return expressionType; } + @NotNull + public static JetTypeInfo checkImplicitCast(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) { + return typeInfo.replaceType(checkImplicitCast(typeInfo.getType(), expression, context, isStatement)); + } + @NotNull public static JetTypeInfo illegalStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) { facade.checkStatementType( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java index e7238fa8e83..be50b0ae400 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorForStatements.java @@ -228,7 +228,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito else { return facade.getTypeInfo(expression, context); } - return result.checkType(expression, context); + return DataFlowUtils.checkType(result, expression, context); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt index 67e49294403..b13a7371986 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt @@ -42,12 +42,6 @@ import org.jetbrains.kotlin.types.JetType fun clearType() = replaceType(null) - fun checkType(expression: JetExpression, context: ResolutionContext<*>) = - replaceType(DataFlowUtils.checkType(type, expression, context)) - - fun checkImplicitCast(expression: JetExpression, context: ResolutionContext<*>, isStatement: Boolean) = - replaceType(DataFlowUtils.checkImplicitCast(type, expression, context, isStatement)) - // NB: do not compare type with this.type because this comparison is complex and unstabld fun replaceType(type: JetType?) = JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo) @@ -57,10 +51,12 @@ import org.jetbrains.kotlin.types.JetType fun replaceJumpFlowInfo(jumpFlowInfo: DataFlowInfo) = if (jumpFlowInfo == this.jumpFlowInfo) this else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo) - fun replaceDataFlowInfo(dataFlowInfo: DataFlowInfo) = - if (dataFlowInfo == this.dataFlowInfo) this - // If jump flow information was the same, it should be changed together - else if (this.dataFlowInfo == jumpFlowInfo) JetTypeInfo(type, dataFlowInfo, jumpOutPossible, dataFlowInfo) - // Otherwise they are changed separately - else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo) + fun replaceDataFlowInfo(dataFlowInfo: DataFlowInfo) = when (this.dataFlowInfo) { + // Nothing changed + dataFlowInfo -> this + // Jump info is the same as data flow info: change both + jumpFlowInfo -> JetTypeInfo(type, dataFlowInfo, jumpOutPossible, dataFlowInfo) + // Jump info is not the same: change data flow info only + else -> JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo) + } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java index d14483e86af..919fb890588 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java @@ -63,7 +63,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { DataFlowInfo newDataFlowInfo = conditionInfo.and(typeInfo.getDataFlowInfo()); context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo); } - return typeInfo.replaceType(KotlinBuiltIns.getInstance().getBooleanType()).checkType(expression, contextWithExpectedType); + return DataFlowUtils.checkType(typeInfo.replaceType(KotlinBuiltIns.getInstance().getBooleanType()), expression, contextWithExpectedType); } @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt index 5722f77830d..16808b5843f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.expressions.DataFlowUtils import org.jetbrains.kotlin.types.expressions.JetTypeInfo /* @@ -40,4 +41,4 @@ public fun noTypeInfo(dataFlowInfo: DataFlowInfo): JetTypeInfo = createTypeInfo( public fun noTypeInfo(context: ResolutionContext<*>): JetTypeInfo = noTypeInfo(context.dataFlowInfo) public fun createCheckedTypeInfo(type: JetType?, context: ResolutionContext<*>, expression: JetExpression): JetTypeInfo = - createTypeInfo(type, context).checkType(expression, context) + DataFlowUtils.checkType(createTypeInfo(type, context), expression, context) diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt index d8c26b3ecf8..65127af0d98 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt @@ -3,7 +3,9 @@ fun bar(): Boolean { return true } public fun foo(x: String?): Int { var y: Any do { - y = "" + // This and hashCode() below are needed just to prevent + // UNINITIALIZED_VARIABLE, UNUSED_VALUE, ... + y = "" y = if (x == null) break else x } while (bar()) y.hashCode()