From 27625b04e19fbb7da592a8a02feec19626e6700b Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 20 Apr 2015 16:12:49 +0300 Subject: [PATCH] Refactoring of JetTypeInfo / BindingContext. Loop data flow analysis corrected. Now BindingContext includes expression type info instead of jump out possible, data flow info and expression type. getType() was added into BindingContext, getType() and recordType() were added into BindingTrace. JetTypeInfo now includes also jump possible flag and jump point data flow info. Old TypeInfoWithJumpInfo deleted. TypeInfoFactory introduced to create JetTypeInfo instances. A pack of extra tests for break / continue in loops added. --- .../kotlin/codegen/ExpressionCodegen.java | 32 +-- .../codegen/ImplementationBodyCodegen.java | 4 +- .../kotlin/codegen/MemberCodegen.java | 2 +- .../kotlin/codegen/PropertyCodegen.java | 2 +- .../binding/CodegenAnnotatingVisitor.java | 2 +- .../kotlin/codegen/when/SwitchCodegen.java | 4 +- .../load/kotlin/KotlinJvmCheckerProvider.kt | 6 +- .../jetbrains/kotlin/analyzer/AnalyzerUtil.kt | 4 +- .../kotlin/cfg/JetControlFlowProcessor.java | 2 +- .../org/jetbrains/kotlin/cfg/WhenChecker.java | 6 +- .../kotlin/cfg/pseudocode/PseudocodeUtil.java | 11 + .../kotlin/checkers/DebugInfoUtil.java | 2 +- .../kotlin/resolve/AnnotationResolver.java | 2 +- .../kotlin/resolve/BindingContext.java | 17 +- .../kotlin/resolve/BindingContextUtils.java | 29 +- .../kotlin/resolve/BindingContextUtils.kt | 13 +- .../kotlin/resolve/BindingTrace.java | 14 + .../kotlin/resolve/BindingTraceContext.java | 25 ++ .../kotlin/resolve/CompositeBindingContext.kt | 7 +- .../resolve/DelegatedPropertyResolver.java | 2 +- .../resolve/DelegatingBindingTrace.java | 30 +++ .../resolve/ObservableBindingTrace.java | 14 + .../kotlin/resolve/TemporaryBindingTrace.java | 2 + .../resolve/calls/ArgumentTypeResolver.java | 9 +- .../kotlin/resolve/calls/CallCompleter.kt | 6 +- .../resolve/calls/CallExpressionResolver.java | 46 ++-- .../resolve/calls/CandidateResolver.java | 1 + .../calls/smartcasts/SmartCastUtils.java | 3 +- .../kotlin/resolve/calls/util/callUtil.kt | 2 +- .../evaluate/ConstantExpressionEvaluator.kt | 2 +- .../resolve/scopes/receivers/Qualifier.kt | 3 +- .../LockBasedLazyResolveStorageManager.kt | 10 + .../jetbrains/kotlin/types/JetTypeInfo.java | 53 ---- .../BasicExpressionTypingVisitor.java | 250 +++++++++--------- .../ControlStructureTypingUtils.java | 2 +- .../ControlStructureTypingVisitor.java | 98 ++++--- .../types/expressions/DataFlowUtils.java | 36 +-- .../expressions/ExpressionTypingFacade.java | 2 - .../ExpressionTypingInternals.java | 1 - .../expressions/ExpressionTypingServices.java | 24 +- .../expressions/ExpressionTypingUtils.java | 6 +- .../expressions/ExpressionTypingVisitor.java | 1 - .../ExpressionTypingVisitorDispatcher.java | 42 +-- .../ExpressionTypingVisitorForStatements.java | 64 +++-- .../expressions/FunctionsTypingVisitor.kt | 17 +- .../kotlin/types/expressions/JetTypeInfo.kt | 66 +++++ .../PatternMatchingTypingVisitor.java | 22 +- .../types/expressions/TypeInfoFactory.kt | 43 +++ .../types/expressions/TypeInfoWithJumpInfo.kt | 46 ---- .../assignElvisIfBreakInsideWhileTrue.kt | 11 + .../assignElvisIfBreakInsideWhileTrue.txt | 3 + .../loops/assignWhenInsideWhileTrue.kt | 15 ++ .../loops/assignWhenInsideWhileTrue.txt | 3 + .../loops/ifBreakAssignInsideDoWhile.kt | 12 + .../loops/ifBreakAssignInsideDoWhile.txt | 4 + .../loops/ifBreakAssignInsideWhileTrue.kt | 10 + .../loops/ifBreakAssignInsideWhileTrue.txt | 3 + .../loops/ifBreakExprInsideWhileTrue.kt | 10 + .../loops/ifBreakExprInsideWhileTrue.txt | 3 + .../loops/leftElvisBreakInsideWhileTrue.kt | 11 + .../loops/leftElvisBreakInsideWhileTrue.txt | 3 + .../loops/plusAssignWhenInsideDoWhile.kt | 20 ++ .../loops/plusAssignWhenInsideDoWhile.txt | 4 + .../smartCasts/loops/whenInsideWhileTrue.kt | 12 + .../smartCasts/loops/whenInsideWhileTrue.txt | 3 + .../loops/whenReturnInsideWhileTrue.kt | 13 + .../loops/whenReturnInsideWhileTrue.txt | 3 + .../checkers/JetDiagnosticsTestGenerated.java | 54 ++++ .../kotlin/resolve/ExpectedResolveData.java | 2 +- .../jetbrains/kotlin/test/JetTestUtils.java | 36 +++ .../codeInsight/ReferenceVariantsHelper.kt | 6 +- .../intentions/OperatorToFunctionIntention.kt | 2 +- .../kotlin/idea/completion/ExpectedInfos.kt | 10 +- .../idea/completion/smart/SmartCompletion.kt | 4 +- .../kotlin/idea/core/KotlinIndicesHelper.kt | 2 +- .../kotlin/idea/core/SmartCastCalculator.kt | 2 +- .../kotlin/idea/core/descriptorUtils.kt | 2 +- .../core/refactoring/JetNameSuggester.java | 2 +- .../actions/ShowExpressionTypeAction.java | 4 +- .../internal/CheckPartialBodyResolveAction.kt | 2 +- .../internal/FindImplicitNothingAction.kt | 2 +- .../KotlinExpressionSurrounder.java | 2 +- .../expression/KotlinNotSurrounder.java | 2 +- .../KotlinRuntimeTypeCastSurrounder.kt | 2 +- .../expression/KotlinWhenSurrounder.java | 2 +- .../ConvertToConcatenatedStringIntention.kt | 2 +- .../ConvertToExpressionBodyIntention.kt | 2 +- .../ConvertToStringTemplateIntention.kt | 4 +- .../ReplaceWithInfixFunctionCallIntention.kt | 2 +- .../jetbrains/kotlin/idea/intentions/Utils.kt | 2 +- .../declarations/DeclarationUtils.java | 4 +- .../JetFunctionParameterInfoHandler.java | 2 +- .../quickfix/AddFunctionParametersFix.java | 2 +- .../idea/quickfix/AddNameToArgumentFix.java | 2 +- .../idea/quickfix/CastExpressionFix.java | 2 +- .../ChangeFunctionLiteralReturnTypeFix.java | 2 +- .../quickfix/ChangeFunctionSignatureFix.java | 4 +- .../quickfix/DeprecatedLambdaSyntaxFix.kt | 2 +- .../QuickFixFactoryForTypeMismatchError.java | 4 +- .../callableBuilder/typeUtils.kt | 18 +- .../CreateCallableFromCallActionFactory.kt | 2 +- .../idea/refactoring/JetRefactoringUtil.java | 2 +- .../JetChangeSignatureUsageProcessor.java | 2 +- .../extractableAnalysisUtil.kt | 10 +- .../KotlinIntroduceParameterHandler.kt | 2 +- .../KotlinIntroduceVariableHandler.java | 2 +- .../util/psi/patternMatching/JetPsiUnifier.kt | 2 +- .../resolve/AbstractPartialBodyResolveTest.kt | 2 +- .../expression/ExpressionVisitor.java | 2 +- .../expression/StringTemplateTranslator.java | 2 +- .../operation/UnaryOperationTranslator.java | 2 +- .../js/translate/utils/BindingUtils.java | 4 +- .../js/translate/utils/JsDescriptorUtils.java | 2 +- 113 files changed, 908 insertions(+), 550 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/kotlin/types/JetTypeInfo.java create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt delete mode 100644 compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoWithJumpInfo.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 12f38d63f19..dc4c1b055b3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -376,14 +376,14 @@ public class ExpressionCodegen extends JetVisitor implem } @NotNull - public Type expressionType(JetExpression expression) { + public Type expressionType(@Nullable JetExpression expression) { JetType type = expressionJetType(expression); return type == null ? Type.VOID_TYPE : asmType(type); } @Nullable - public JetType expressionJetType(JetExpression expression) { - return bindingContext.get(EXPRESSION_TYPE, expression); + public JetType expressionJetType(@Nullable JetExpression expression) { + return expression != null ? bindingContext.getType(expression) : null; } @Override @@ -534,7 +534,7 @@ public class ExpressionCodegen extends JetVisitor implem } JetExpression loopRange = forExpression.getLoopRange(); - JetType loopRangeType = bindingContext.get(EXPRESSION_TYPE, loopRange); + JetType loopRangeType = bindingContext.getType(loopRange); assert loopRangeType != null; Type asmLoopRangeType = asmType(loopRangeType); if (asmLoopRangeType.getSort() == Type.ARRAY) { @@ -818,7 +818,7 @@ public class ExpressionCodegen extends JetVisitor implem private ForInArrayLoopGenerator(@NotNull JetForExpression forExpression) { super(forExpression); - loopRangeType = bindingContext.get(EXPRESSION_TYPE, forExpression.getLoopRange()); + loopRangeType = bindingContext.getType(forExpression.getLoopRange()); } @Override @@ -1029,7 +1029,7 @@ public class ExpressionCodegen extends JetVisitor implem @Override protected void storeRangeStartAndEnd() { - JetType loopRangeType = bindingContext.get(EXPRESSION_TYPE, forExpression.getLoopRange()); + JetType loopRangeType = bindingContext.getType(forExpression.getLoopRange()); assert loopRangeType != null; Type asmLoopRangeType = asmType(loopRangeType); gen(forExpression.getLoopRange(), asmLoopRangeType); @@ -1061,7 +1061,7 @@ public class ExpressionCodegen extends JetVisitor implem incrementVar = createLoopTempVariable(asmElementType); - JetType loopRangeType = bindingContext.get(EXPRESSION_TYPE, forExpression.getLoopRange()); + JetType loopRangeType = bindingContext.getType(forExpression.getLoopRange()); assert loopRangeType != null; Type asmLoopRangeType = asmType(loopRangeType); @@ -1286,7 +1286,7 @@ public class ExpressionCodegen extends JetVisitor implem public static CompileTimeConstant getCompileTimeConstant(@NotNull JetExpression expression, @NotNull BindingContext bindingContext) { CompileTimeConstant compileTimeValue = bindingContext.get(COMPILE_TIME_VALUE, expression); if (compileTimeValue instanceof IntegerValueTypeConstant) { - JetType expectedType = bindingContext.get(EXPRESSION_TYPE, expression); + JetType expectedType = bindingContext.getType(expression); assert expectedType != null : "Expression is not type checked: " + expression.getText(); return EvaluatePackage.createCompileTimeConstantWithType((IntegerValueTypeConstant) compileTimeValue, expectedType); } @@ -2664,7 +2664,7 @@ public class ExpressionCodegen extends JetVisitor implem public StackValue visitClassLiteralExpression(@NotNull JetClassLiteralExpression expression, StackValue data) { checkReflectionIsAvailable(expression); - JetType type = bindingContext.get(EXPRESSION_TYPE, expression); + JetType type = bindingContext.getType(expression); assert type != null; assert state.getReflectionTypes().getkClass().getTypeConstructor().equals(type.getConstructor()) @@ -3384,7 +3384,7 @@ public class ExpressionCodegen extends JetVisitor implem JetExpression initializer = multiDeclaration.getInitializer(); if (initializer == null) return StackValue.none(); - JetType initializerType = bindingContext.get(EXPRESSION_TYPE, initializer); + JetType initializerType = bindingContext.getType(initializer); assert initializerType != null; Type initializerAsmType = asmType(initializerType); @@ -3491,7 +3491,7 @@ public class ExpressionCodegen extends JetVisitor implem } public StackValue generateNewArray(@NotNull JetCallExpression expression) { - JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression); + JetType arrayType = bindingContext.getType(expression); assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText(); return generateNewArray(expression, arrayType); @@ -3531,7 +3531,7 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, StackValue receiver) { JetExpression array = expression.getArrayExpression(); - JetType type = bindingContext.get(EXPRESSION_TYPE, array); + JetType type = bindingContext.getType(array); Type arrayType = expressionType(array); List indices = expression.getIndexExpressions(); FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression); @@ -3640,7 +3640,7 @@ The "returned" value of try expression with no finally is either the last expres (or blocks). */ - JetType jetType = bindingContext.get(EXPRESSION_TYPE, expression); + JetType jetType = bindingContext.getType(expression); assert jetType != null; final Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType); @@ -3808,7 +3808,7 @@ The "returned" value of try expression with no finally is either the last expres v.dup(); Label nonnull = new Label(); v.ifnonnull(nonnull); - JetType leftType = bindingContext.get(EXPRESSION_TYPE, left); + JetType leftType = bindingContext.getType(left); assert leftType != null; genThrow(v, "kotlin/TypeCastException", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(leftType) + " cannot be cast to " + @@ -3847,7 +3847,7 @@ The "returned" value of try expression with no finally is either the last expres if (expressionToMatch != null) { Type subjectType = expressionToMatch.type; markStartLineNumber(patternExpression); - JetType condJetType = bindingContext.get(EXPRESSION_TYPE, patternExpression); + JetType condJetType = bindingContext.getType(patternExpression); Type condType; if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) { assert condJetType != null; @@ -4051,7 +4051,7 @@ The "returned" value of try expression with no finally is either the last expres if (rangeExpression instanceof JetBinaryExpression) { JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression; if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) { - JetType jetType = bindingContext.get(EXPRESSION_TYPE, rangeExpression); + JetType jetType = bindingContext.getType(rangeExpression); assert jetType != null; DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor(); return INTEGRAL_RANGES.contains(descriptor); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index de5591535fc..d4d0cb752e9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -1266,7 +1266,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { result.addField((JetDelegatorByExpressionSpecifier) specifier, propertyDescriptor); } else { - JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); + JetType expressionType = bindingContext.getType(expression); Type asmType = expressionType != null ? typeMapper.mapType(expressionType) : typeMapper.mapType(getSuperClass(specifier)); result.addField((JetDelegatorByExpressionSpecifier) specifier, asmType, "$delegate_" + n); @@ -1718,7 +1718,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { DelegationFieldsInfo.Field field = delegationFieldsInfo.getInfo((JetDelegatorByExpressionSpecifier) specifier); generateDelegateField(field); JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); - JetType delegateExpressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, delegateExpression); + JetType delegateExpressionType = bindingContext.getType(delegateExpression); generateDelegates(getSuperClass(specifier), delegateExpressionType, field); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index cdf7066dd90..f1a59a0fadf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -395,7 +395,7 @@ public abstract class MemberCodegen if (expression.getOperationToken() == JetTokens.EXCLEXCL) { val baseExpression = expression.getBaseExpression() - val baseExpressionType = c.trace.get(BindingContext.EXPRESSION_TYPE, baseExpression) ?: return + val baseExpressionType = c.trace.getType(baseExpression) ?: return doIfNotNull( DataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c), c @@ -228,7 +228,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker { when (expression.getOperationToken()) { JetTokens.ELVIS -> { val baseExpression = expression.getLeft() - val baseExpressionType = c.trace.get(BindingContext.EXPRESSION_TYPE, baseExpression) ?: return + val baseExpressionType = c.trace.getType(baseExpression) ?: return doIfNotNull( DataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c), c @@ -243,7 +243,7 @@ public class JavaNullabilityWarningsChecker : AdditionalTypeChecker { if (expression.getLeft() != null && expression.getRight() != null) { SenselessComparisonChecker.checkSenselessComparisonWithNull( expression, expression.getLeft()!!, expression.getRight()!!, c, - { c.trace.get(BindingContext.EXPRESSION_TYPE, it) }, + { c.trace.getType(it) }, { value -> doIfNotNull(value, c) { Nullability.NOT_NULL } ?: Nullability.UNKNOWN diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerUtil.kt index 2e39f41dfb2..cd5d4dd1082 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalyzerUtil.kt @@ -23,12 +23,12 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.types.JetTypeInfo import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTraceContext import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.types.expressions.JetTypeInfo public fun JetExpression.computeTypeInfoInContext( scope: JetScope, @@ -59,7 +59,7 @@ public fun JetExpression.computeTypeInContext( expectedType: JetType = TypeUtils.NO_EXPECTED_TYPE, module: ModuleDescriptor = scope.getModule() ): JetType { - return computeTypeInfoInContext(scope, trace, dataFlowInfo, expectedType, module).getType().safeType(this) + return computeTypeInfoInContext(scope, trace, dataFlowInfo, expectedType, module).type.safeType(this) } public fun JetType?.safeType(expression: JetExpression): JetType { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java index 445610f6be3..f96be622e08 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java @@ -190,7 +190,7 @@ public class JetControlFlowProcessor { return; } - JetType type = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, expression); + JetType type = trace.getBindingContext().getType(expression); if (type != null && KotlinBuiltIns.isNothing(type)) { builder.jumpToError(expression); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java index 358d44408e1..bafe3c5e98e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.TypeUtils; -import static org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; public final class WhenChecker { @@ -63,7 +62,7 @@ public final class WhenChecker { @Nullable private static JetType whenSubjectType(@NotNull JetWhenExpression expression, @NotNull BindingContext context) { JetExpression subjectExpression = expression.getSubjectExpression(); - return subjectExpression == null ? null : context.get(EXPRESSION_TYPE, subjectExpression); + return subjectExpression == null ? null : context.getType(subjectExpression); } private static boolean isWhenExhaustive(@NotNull JetWhenExpression expression, @NotNull BindingTrace trace) { @@ -112,8 +111,7 @@ public final class WhenChecker { for (JetWhenEntry entry : expression.getEntries()) { for (JetWhenCondition condition : entry.getConditions()) { if (condition instanceof JetWhenConditionWithExpression) { - JetType type = trace.getBindingContext().get( - EXPRESSION_TYPE, ((JetWhenConditionWithExpression) condition).getExpression() + JetType type = trace.getBindingContext().getType(((JetWhenConditionWithExpression) condition).getExpression() ); if (type != null && KotlinBuiltIns.isNothingOrNullableNothing(type)) { return true; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java index 5fca2e4000b..31360d9cd6c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilPackage; +import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; @@ -64,6 +65,16 @@ public class PseudocodeUtil { return bindingContext.getKeys(slice); } + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + return bindingContext.getType(expression); + } + + @Override + public void recordType(@NotNull JetExpression expression, @Nullable JetType type) { + } + @Override public void report(@NotNull Diagnostic diagnostic) { } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/checkers/DebugInfoUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/checkers/DebugInfoUtil.java index 50d853ddc18..0d64822b3cb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/checkers/DebugInfoUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/checkers/DebugInfoUtil.java @@ -196,7 +196,7 @@ public class DebugInfoUtil { // if 'foo' in 'foo[i]' is unresolved it means 'foo[i]' is unresolved (otherwise 'foo[i]' is marked as 'missing unresolved') markedWithError = true; } - JetType expressionType = bindingContext.get(EXPRESSION_TYPE, expression); + JetType expressionType = bindingContext.getType(expression); DiagnosticFactory factory = markedWithErrorElements.get(expression); if (declarationDescriptor != null && (ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java index 4792eeee081..3190fbcac58 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationResolver.java @@ -280,7 +280,7 @@ public class AnnotationResolver { @NotNull JetType expectedType, @NotNull BindingTrace trace ) { - JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression); + JetType expressionType = trace.getType(argumentExpression); if (expressionType == null || !JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, expectedType)) { // TYPE_MISMATCH should be reported otherwise diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 303d2022b7d..4afcf0688dc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.types.Approximation; import org.jetbrains.kotlin.types.DeferredType; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.expressions.CaptureKind; +import org.jetbrains.kotlin.types.expressions.JetTypeInfo; import org.jetbrains.kotlin.util.Box; import org.jetbrains.kotlin.util.slicedMap.*; @@ -73,6 +74,11 @@ public interface BindingContext { public ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice) { return ImmutableMap.of(); } + + @Nullable + public JetType getType(@NotNull JetExpression expression) { + return null; + } }; WritableSlice ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT = Slices.createSimpleSlice(); @@ -82,18 +88,12 @@ public interface BindingContext { WritableSlice> COMPILE_TIME_VALUE = Slices.createSimpleSlice(); WritableSlice TYPE = Slices.createSimpleSlice(); - WritableSlice EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); + WritableSlice EXPRESSION_TYPE_INFO = new BasicWritableSlice(DO_NOTHING); WritableSlice EXPECTED_EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); WritableSlice EXPECTED_RETURN_TYPE = new BasicWritableSlice(DO_NOTHING); - WritableSlice EXPRESSION_DATA_FLOW_INFO = new BasicWritableSlice(DO_NOTHING); WritableSlice EXPRESSION_RESULT_APPROXIMATION = new BasicWritableSlice(DO_NOTHING); WritableSlice DATAFLOW_INFO_AFTER_CONDITION = Slices.createSimpleSlice(); - /** - * Expression has jump out of the loop (break/continue) inside - */ - WritableSlice EXPRESSION_JUMP_OUT_POSSIBLE = new BasicWritableSlice(DO_NOTHING); - /** * A qualifier corresponds to a receiver expression (if any). For 'A.B' qualifier is recorded for 'A'. */ @@ -262,4 +262,7 @@ public interface BindingContext { @TestOnly @NotNull ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice); + + @Nullable + JetType getType(@NotNull JetExpression expression); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java index b14553bec79..d59d0f1dd28 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.java @@ -24,14 +24,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.TypeUtils; -import org.jetbrains.kotlin.types.expressions.TypeInfoWithJumpInfo; +import org.jetbrains.kotlin.types.expressions.JetTypeInfo; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice; import java.util.Collection; @@ -81,6 +81,18 @@ public class BindingContextUtils { return getNotNull(bindingContext, slice, key, "Value at " + slice + " must not be null for " + key); } + @NotNull + public static JetType getNotNullType( + @NotNull BindingContext bindingContext, + @NotNull JetExpression expression + ) { + JetType result = bindingContext.getType(expression); + if (result == null) { + throw new IllegalStateException("Type must be not null for " + expression); + } + return result; + } + @NotNull public static V getNotNull( @NotNull BindingContext bindingContext, @@ -139,17 +151,16 @@ public class BindingContextUtils { if (shouldBeMadeNullable) { type = TypeUtils.makeNullable(type); } - trace.record(BindingContext.EXPRESSION_TYPE, expression, type); + trace.recordType(expression, type); return type; } @Nullable - public static TypeInfoWithJumpInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) { - if (!context.get(BindingContext.PROCESSED, expression)) return null; - DataFlowInfo dataFlowInfo = BindingContextUtilPackage.getDataFlowInfo(context, expression); - JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression); - Boolean jumpOutPossible = context.get(BindingContext.EXPRESSION_JUMP_OUT_POSSIBLE, expression); - return new TypeInfoWithJumpInfo(type, dataFlowInfo, Boolean.TRUE.equals(jumpOutPossible), dataFlowInfo); + public static JetTypeInfo getRecordedTypeInfo(@NotNull JetExpression expression, @NotNull BindingContext context) { + // 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.createTypeInfo(DataFlowInfo.EMPTY); } public static boolean isExpressionWithValidReference( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt index d4cc0fab90a..73727214c73 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingContext): FunctionDescriptor? { val targetLabel = getTargetLabel() @@ -40,7 +41,7 @@ public fun JetReturnExpression.getTargetFunctionDescriptor(context: BindingConte val containingFunctionDescriptor = DescriptorUtils.getParentOfType(declarationDescriptor, javaClass(), false) if (containingFunctionDescriptor == null) return null - return stream(containingFunctionDescriptor) { DescriptorUtils.getParentOfType(it, javaClass()) } + return sequence(containingFunctionDescriptor) { DescriptorUtils.getParentOfType(it, javaClass()) } .dropWhile { it is AnonymousFunctionDescriptor } .firstOrNull() } @@ -57,13 +58,17 @@ public fun > ResolutionContext.recordScopeAndDataFlo if (expression == null) return trace.record(BindingContext.RESOLUTION_SCOPE, expression, scope) - if (dataFlowInfo != DataFlowInfo.EMPTY) { - trace.record(BindingContext.EXPRESSION_DATA_FLOW_INFO, expression, dataFlowInfo) + val typeInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression) + if (typeInfo != null) { + trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo.replaceDataFlowInfo(dataFlowInfo)) + } + else if (dataFlowInfo != DataFlowInfo.EMPTY) { + trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, createTypeInfo(dataFlowInfo)) } } public fun BindingContext.getDataFlowInfo(expression: JetExpression?): DataFlowInfo = - expression?.let { this[BindingContext.EXPRESSION_DATA_FLOW_INFO, it] } ?: DataFlowInfo.EMPTY + expression?.let { this[BindingContext.EXPRESSION_TYPE_INFO, it]?.dataFlowInfo } ?: DataFlowInfo.EMPTY public fun JetExpression.isUnreachableCode(context: BindingContext): Boolean = context[BindingContext.UNREACHABLE_CODE, this]!! diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTrace.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTrace.java index b7782bc95b1..7c9792da92d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTrace.java @@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.diagnostics.DiagnosticSink; +import org.jetbrains.kotlin.psi.JetExpression; +import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; @@ -40,4 +42,16 @@ public interface BindingTrace extends DiagnosticSink { // slice.isCollective() must be true @NotNull Collection getKeys(WritableSlice slice); + + /** + * Expression type should be taken from EXPRESSION_TYPE_INFO slice + */ + @Nullable + JetType getType(@NotNull JetExpression expression); + + /** + * Expression type should be recorded into EXPRESSION_TYPE_INFO slice + * (either updated old or a new one) + */ + void recordType(@NotNull JetExpression expression, @Nullable JetType type); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java index 5f3c6fe0664..0140841ebed 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java @@ -18,10 +18,15 @@ package org.jetbrains.kotlin.resolve; import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.diagnostics.Diagnostic; +import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression; +import org.jetbrains.kotlin.types.JetType; +import org.jetbrains.kotlin.types.expressions.JetTypeInfo; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import org.jetbrains.kotlin.util.slicedMap.*; import java.util.Collection; @@ -59,6 +64,12 @@ public class BindingTraceContext implements BindingTrace { public ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice) { return map.getSliceContents(slice); } + + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + return BindingTraceContext.this.getType(expression); + } }; public BindingTraceContext() { @@ -112,4 +123,18 @@ public class BindingTraceContext implements BindingTrace { public Collection getKeys(WritableSlice slice) { return map.getKeys(slice); } + + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression); + return typeInfo != null ? typeInfo.getType() : null; + } + + @Override + public void recordType(@NotNull JetExpression expression, @Nullable JetType type) { + JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression); + typeInfo = typeInfo != null ? typeInfo.replaceType(type) : TypeInfoFactoryPackage.createTypeInfo(type); + record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo); + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompositeBindingContext.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompositeBindingContext.kt index a76a75a4f3e..3c227fab016 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompositeBindingContext.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/CompositeBindingContext.kt @@ -22,11 +22,16 @@ import com.google.common.collect.ImmutableMap import org.jetbrains.kotlin.diagnostics.Diagnostic import com.intellij.psi.PsiElement import com.intellij.openapi.util.ModificationTracker +import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +import org.jetbrains.kotlin.types.JetType public class CompositeBindingContext private ( private val delegates: List ) : BindingContext { + override fun getType(expression: JetExpression): JetType? { + return delegates.sequence().map { it.getType(expression) }.firstOrNull { it != null } + } companion object { public fun create(delegates: List): BindingContext { @@ -37,7 +42,7 @@ public class CompositeBindingContext private ( } override fun get(slice: ReadOnlySlice?, key: K?): V? { - return delegates.stream().map { it[slice, key] }.firstOrNull { it != null } + return delegates.sequence().map { it[slice, key] }.firstOrNull { it != null } } override fun getKeys(slice: WritableSlice?): Collection { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java index a01d13543e7..4813c60b7d9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java @@ -265,7 +265,7 @@ public class DelegatedPropertyResolver { builder.append("("); List argumentTypes = Lists.newArrayList(); for (ValueArgument argument : call.getValueArguments()) { - argumentTypes.add(context.get(EXPRESSION_TYPE, argument.getArgumentExpression())); + argumentTypes.add(context.getType(argument.getArgumentExpression())); } builder.append(Renderers.RENDER_COLLECTION_OF_TYPES.render(argumentTypes)); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.java index db48e3e785f..d1adff35931 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.java @@ -23,8 +23,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.diagnostics.Diagnostic; +import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression; +import org.jetbrains.kotlin.types.JetType; +import org.jetbrains.kotlin.types.expressions.JetTypeInfo; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import org.jetbrains.kotlin.util.slicedMap.*; import java.util.Collection; @@ -51,6 +55,13 @@ public class DelegatingBindingTrace implements BindingTrace { return DelegatingBindingTrace.this.get(slice, key); } + + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + return DelegatingBindingTrace.this.getType(expression); + } + @NotNull @Override public Collection getKeys(WritableSlice slice) { @@ -122,6 +133,25 @@ public class DelegatingBindingTrace implements BindingTrace { return result; } + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression); + return typeInfo != null ? typeInfo.getType() : null; + } + + @Override + public void recordType(@NotNull JetExpression expression, @Nullable JetType type) { + JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression); + if (typeInfo == null) { + typeInfo = TypeInfoFactoryPackage.createTypeInfo(type); + } + else { + typeInfo = typeInfo.replaceType(type); + } + record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo); + } + public void addAllMyDataTo(@NotNull BindingTrace trace) { addAllMyDataTo(trace, null, true); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java index 862c9263ce7..770eea8ba46 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java @@ -18,7 +18,10 @@ package org.jetbrains.kotlin.resolve; import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.diagnostics.Diagnostic; +import org.jetbrains.kotlin.psi.JetExpression; +import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; @@ -74,6 +77,17 @@ public class ObservableBindingTrace implements BindingTrace { return originalTrace.getKeys(slice); } + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + return originalTrace.getType(expression); + } + + @Override + public void recordType(@NotNull JetExpression expression, @Nullable JetType type) { + originalTrace.recordType(expression, type); + } + public ObservableBindingTrace addHandler(@NotNull WritableSlice slice, @NotNull RecordHandler handler) { handlers.put(slice, handler); return this; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java index 380022a9e8d..247af5c0d38 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java @@ -18,6 +18,8 @@ package org.jetbrains.kotlin.resolve; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.psi.JetExpression; +import org.jetbrains.kotlin.types.JetType; public class TemporaryBindingTrace extends DelegatingBindingTrace { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java index 49044196f31..1d846ff5b0f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ArgumentTypeResolver.java @@ -37,11 +37,12 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.JetTypeInfo; import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.checker.JetTypeChecker; import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; +import org.jetbrains.kotlin.types.expressions.JetTypeInfo; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import javax.inject.Inject; import java.util.Collections; @@ -191,7 +192,7 @@ public class ArgumentTypeResolver { @NotNull ResolveArgumentsMode resolveArgumentsMode ) { if (expression == null) { - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } if (isFunctionLiteralArgument(expression, context)) { return getFunctionLiteralTypeInfo(expression, getFunctionLiteralArgument(expression, context), context, resolveArgumentsMode); @@ -214,7 +215,7 @@ public class ArgumentTypeResolver { ) { if (resolveArgumentsMode == SHAPE_FUNCTION_ARGUMENTS) { JetType type = getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, true); - return JetTypeInfo.create(type, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(type, context); } return expressionTypingServices.getTypeInfo(expression, context.replaceContextDependency(INDEPENDENT)); } @@ -297,7 +298,7 @@ public class ArgumentTypeResolver { @NotNull ResolutionContext context, @NotNull JetExpression expression ) { - JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, expression); + JetType type = context.trace.getType(expression); if (type != null && !type.getConstructor().isDenotable()) { if (type.getConstructor() instanceof IntegerValueTypeConstructor) { IntegerValueTypeConstructor constructor = (IntegerValueTypeConstructor) type.getConstructor(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index 257b0d1978a..3ad6b26b97c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -229,7 +229,7 @@ public class CallCompleter( val deparenthesized = ArgumentTypeResolver.getLastElementDeparenthesized(expression, context) if (deparenthesized == null) return - val recordedType = context.trace[BindingContext.EXPRESSION_TYPE, expression] + val recordedType = context.trace.getType(expression) var updatedType: JetType? = recordedType val results = completeCallForArgument(deparenthesized, context) @@ -304,7 +304,7 @@ public class CallCompleter( BindingContextUtils.updateRecordedType( updatedType, expression, trace, /* shouldBeMadeNullable = */ hasNecessarySafeCall(expression, trace)) } - return trace[BindingContext.EXPRESSION_TYPE, argumentExpression] + return trace.getType(argumentExpression) } private fun hasNecessarySafeCall(expression: JetExpression, trace: BindingTrace): Boolean { @@ -315,7 +315,7 @@ public class CallCompleter( if (expression !is JetSafeQualifiedExpression) return false //If a receiver type is not null, then this safe expression is useless, and we don't need to make the result type nullable. - val expressionType = trace[BindingContext.EXPRESSION_TYPE, expression.getReceiverExpression()] + val expressionType = trace.getType(expression.getReceiverExpression()) return expressionType != null && TypeUtils.isNullableType(expressionType) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java index 672776e0592..90bfb663562 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java @@ -44,12 +44,9 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat import org.jetbrains.kotlin.resolve.scopes.receivers.*; import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.JetTypeInfo; import org.jetbrains.kotlin.types.TypeUtils; -import org.jetbrains.kotlin.types.expressions.BasicExpressionTypingVisitor; -import org.jetbrains.kotlin.types.expressions.DataFlowUtils; -import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext; -import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices; +import org.jetbrains.kotlin.types.expressions.*; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import javax.inject.Inject; import java.util.Collections; @@ -136,14 +133,13 @@ public class CallExpressionResolver { context, "trace to resolve as variable", nameExpression); JetType type = getVariableType(nameExpression, receiver, callOperationNode, context.replaceTraceAndCache(temporaryForVariable), result); - DataFlowInfo dataFlowInfo = context.dataFlowInfo; // TODO: for a safe call, it's necessary to set receiver != null here, as inside ArgumentTypeResolver.analyzeArgumentsAndRecordTypes // Unfortunately it provokes problems with x?.y!!.foo() with the following x!!.bar(): // x != null proceeds to successive statements if (result[0]) { temporaryForVariable.commit(); - return JetTypeInfo.create(type, dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(type, context); } Call call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, Collections.emptyList()); @@ -158,11 +154,11 @@ public class CallExpressionResolver { boolean hasValueParameters = functionDescriptor == null || functionDescriptor.getValueParameters().size() > 0; context.trace.report(FUNCTION_CALL_EXPECTED.on(nameExpression, nameExpression, hasValueParameters)); type = functionDescriptor != null ? functionDescriptor.getReturnType() : null; - return JetTypeInfo.create(type, dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(type, context); } temporaryForVariable.commit(); - return JetTypeInfo.create(null, dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } @NotNull @@ -172,7 +168,7 @@ public class CallExpressionResolver { ) { JetTypeInfo typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context); if (context.contextDependency == INDEPENDENT) { - DataFlowUtils.checkType(typeInfo, callExpression, context); + DataFlowUtils.checkType(typeInfo.getType(), callExpression, context); } return typeInfo; } @@ -205,7 +201,7 @@ public class CallExpressionResolver { context.trace.report(FUNCTION_CALL_EXPECTED.on(callExpression, callExpression, hasValueParameters)); } if (functionDescriptor == null) { - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } if (functionDescriptor instanceof ConstructorDescriptor && DescriptorUtils.isAnnotationClass(functionDescriptor.getContainingDeclaration())) { @@ -216,7 +212,7 @@ public class CallExpressionResolver { JetType type = functionDescriptor.getReturnType(); - return JetTypeInfo.create(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo()); + return TypeInfoFactoryPackage.createTypeInfo(type, resolvedCall.getDataFlowInfoForArguments().getResultInfo()); } JetExpression calleeExpression = callExpression.getCalleeExpression(); @@ -230,11 +226,11 @@ public class CallExpressionResolver { temporaryForVariable.commit(); context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression, type != null ? type : ErrorUtils.createErrorType(""))); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } } temporaryForFunction.commit(); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) { @@ -269,7 +265,7 @@ public class CallExpressionResolver { else if (selectorExpression != null) { context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText())); } - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } /** @@ -281,8 +277,8 @@ public class CallExpressionResolver { private final DataFlowInfo safeCallChainInfo; - private JetTypeInfoInsideSafeCall(@Nullable JetType type, @NotNull DataFlowInfo dataFlowInfo, @Nullable DataFlowInfo safeCallChainInfo) { - super(type, dataFlowInfo); + private JetTypeInfoInsideSafeCall(@NotNull JetTypeInfo typeInfo, @Nullable DataFlowInfo safeCallChainInfo) { + super(typeInfo.getType(), typeInfo.getDataFlowInfo(), typeInfo.getJumpOutPossible(), typeInfo.getJumpFlowInfo()); this.safeCallChainInfo = safeCallChainInfo; } @@ -338,12 +334,13 @@ public class CallExpressionResolver { if (selectorReturnType != null && !KotlinBuiltIns.isUnit(selectorReturnType)) { if (TypeUtils.isNullableType(receiverType)) { selectorReturnType = TypeUtils.makeNullable(selectorReturnType); + selectorReturnTypeInfo = selectorReturnTypeInfo.replaceType(selectorReturnType); } } } // TODO : this is suspicious: remove this code? - if (selectorReturnType != null) { - context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType); + if (selectorExpression != null && selectorReturnType != null) { + context.trace.recordType(selectorExpression, selectorReturnType); } CompileTimeConstant value = ConstantExpressionEvaluator.evaluate(expression, context.trace, context.expectedType); @@ -366,7 +363,7 @@ public class CallExpressionResolver { // x?.foo(y!!)?.bar(x.field)?.gav(y.field) (like smartCasts\safecalls\longChain) // Also, we should provide further safe call chain data flow information or // if we are in the most left safe call then just take it from receiver - typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo(), safeCallChainInfo); + typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnTypeInfo, safeCallChainInfo); } else { // Here we should not take selector data flow info into account because it's only one branch, see KT-7204 @@ -375,7 +372,7 @@ public class CallExpressionResolver { // So we should just take safe call chain data flow information, e.g. foo(x!!)?.bar()?.gav() // If it's null, we must take receiver normal info, it's a chain with length of one like foo(x!!)?.bar() and // safe call chain information does not yet exist - typeInfo = JetTypeInfo.create(selectorReturnType, safeCallChainInfo); + typeInfo = selectorReturnTypeInfo.replaceDataFlowInfo(safeCallChainInfo); } } else { @@ -384,17 +381,16 @@ public class CallExpressionResolver { if (context.insideCallChain || safeCallChainInfo == null) { // Not a safe call inside call chain with safe calls OR // call chain without safe calls at all - typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo(), - selectorReturnTypeInfo.getDataFlowInfo()); + typeInfo = new JetTypeInfoInsideSafeCall(selectorReturnTypeInfo, selectorReturnTypeInfo.getDataFlowInfo()); } else { // Exiting call chain with safe calls -- take data flow info from the lest-most receiver // foo(x!!)?.bar().gav() - typeInfo = JetTypeInfo.create(selectorReturnType, safeCallChainInfo); + typeInfo = selectorReturnTypeInfo.replaceDataFlowInfo(safeCallChainInfo); } } if (context.contextDependency == INDEPENDENT) { - DataFlowUtils.checkType(typeInfo, expression, context); + DataFlowUtils.checkType(typeInfo.getType(), expression, context); } return typeInfo; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java index 0ee30300b9f..ad82e8fda2e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.java @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.checker.JetTypeChecker; import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils; +import org.jetbrains.kotlin.types.expressions.JetTypeInfo; import javax.inject.Inject; import java.util.*; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastUtils.java index 343b799d169..3867e4de77a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastUtils.java @@ -42,7 +42,6 @@ import java.util.List; import java.util.Set; import static org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE; -import static org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE; import static org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST; public class SmartCastUtils { @@ -195,7 +194,7 @@ public class SmartCastUtils { if (recordExpressionType) { //TODO //Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary? - trace.record(EXPRESSION_TYPE, expression, type); + trace.recordType(expression, type); } } else { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt index f3b153c8a13..e4299c9dddf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt @@ -69,7 +69,7 @@ public fun > Call.hasUnresolvedArguments(context: Resolu val arguments = getValueArguments().map { it?.getArgumentExpression() } return arguments.any { argument -> - val expressionType = context.trace.getBindingContext()[BindingContext.EXPRESSION_TYPE, argument] + val expressionType = argument?.let { context.trace.getBindingContext().getType(it) } argument != null && !ArgumentTypeResolver.isFunctionLiteralArgument(argument, context) && (expressionType == null || expressionType.isError()) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt index 2c1294b86cb..f84dbba8972 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt @@ -396,7 +396,7 @@ public class ConstantExpressionEvaluator private (val trace: BindingTrace) : Jet } override fun visitClassLiteralExpression(expression: JetClassLiteralExpression, expectedType: JetType?): CompileTimeConstant<*>? { - val jetType = trace.get(BindingContext.EXPRESSION_TYPE, expression) + val jetType = trace.getType(expression) if (jetType.isError()) return null return KClassValue(jetType) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index 91606062a73..25c3a6bc17f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.JetExpression import org.jetbrains.kotlin.psi.JetSimpleNameExpression import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentQualifiedExpressionForSelector -import org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE import org.jetbrains.kotlin.resolve.BindingContext.QUALIFIER import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET import org.jetbrains.kotlin.resolve.BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT @@ -153,7 +152,7 @@ private fun QualifierReceiver.resolveAsReceiverInQualifiedExpression(context: Ex context.trace.report(TYPE_PARAMETER_ON_LHS_OF_DOT.on(referenceExpression, classifier)) } else if (classifier is ClassDescriptor && classifier.hasClassObjectType) { - context.trace.record(EXPRESSION_TYPE, expression, classifier.classObjectType) + context.trace.recordType(expression, classifier.classObjectType) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt index ef7577070c2..e5017e6c5e9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt @@ -24,6 +24,8 @@ import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice import org.jetbrains.kotlin.util.slicedMap.WritableSlice import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import com.intellij.util.containers.ContainerUtil +import org.jetbrains.kotlin.psi.JetExpression +import org.jetbrains.kotlin.types.JetType public class LockBasedLazyResolveStorageManager(private val storageManager: StorageManager): StorageManager by storageManager, LazyResolveStorageManager { override fun createSoftlyRetainedMemoizedFunction(compute: Function1) = @@ -38,6 +40,8 @@ public class LockBasedLazyResolveStorageManager(private val storageManager: Stor LockProtectedTrace(storageManager, originalTrace) private class LockProtectedContext(private val storageManager: StorageManager, private val context: BindingContext) : BindingContext { + override fun getType(expression: JetExpression): JetType? = storageManager.compute { context.getType(expression) } + override fun getDiagnostics(): Diagnostics = storageManager.compute { context.getDiagnostics() } override fun get(slice: ReadOnlySlice, key: K) = storageManager.compute { context.get(slice, key) } @@ -49,6 +53,12 @@ public class LockBasedLazyResolveStorageManager(private val storageManager: Stor } private class LockProtectedTrace(private val storageManager: StorageManager, private val trace: BindingTrace) : BindingTrace { + override fun recordType(expression: JetExpression, type: JetType?) { + storageManager.compute { trace.recordType(expression, type) } + } + + override fun getType(expression: JetExpression): JetType? = storageManager.compute { trace.getType(expression) } + private val context: BindingContext = LockProtectedContext(storageManager, trace.getBindingContext()) override fun getBindingContext() = context diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/JetTypeInfo.java b/compiler/frontend/src/org/jetbrains/kotlin/types/JetTypeInfo.java deleted file mode 100644 index ba6f61fe9c2..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/JetTypeInfo.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.types; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; - -/** - * This class is intended to transfer data flow analysis information in bottom-up direction, - * from AST children to parents. It stores a type of expression under analysis, - * current information about types and nullabilities. - * - * NB: it must be immutable together with all its descendants! - */ -public class JetTypeInfo { - @NotNull - public static JetTypeInfo create(@Nullable JetType type, @NotNull DataFlowInfo dataFlowInfo) { - return new JetTypeInfo(type, dataFlowInfo); - } - - private final JetType type; - private final DataFlowInfo dataFlowInfo; - - protected JetTypeInfo(@Nullable JetType type, @NotNull DataFlowInfo dataFlowInfo) { - this.type = type; - this.dataFlowInfo = dataFlowInfo; - } - - @Nullable - public JetType getType() { - return type; - } - - @NotNull - public DataFlowInfo getDataFlowInfo() { - return dataFlowInfo; - } -} 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 53e9de1cc1f..0c0742291c0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -87,6 +87,7 @@ import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType; import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction; import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*; import static org.jetbrains.kotlin.types.expressions.TypeReconstructionUtil.reconstructBareType; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; @SuppressWarnings("SuspiciousMethodCalls") public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @@ -103,15 +104,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { // TODO : type substitutions??? CallExpressionResolver callExpressionResolver = components.expressionTypingServices.getCallExpressionResolver(); JetTypeInfo typeInfo = callExpressionResolver.getSimpleNameExpressionTypeInfo(expression, NO_RECEIVER, null, context); - JetType type = DataFlowUtils.checkType(typeInfo.getType(), expression, context); - return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); // TODO : Extensions to this + return typeInfo.checkType(expression, context); // TODO : Extensions to this } @Override public JetTypeInfo visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, ExpressionTypingContext context) { JetExpression innerExpression = expression.getExpression(); if (innerExpression == null) { - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } return facade.getTypeInfo(innerExpression, context.replaceScope(context.scope)); } @@ -125,7 +125,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { boolean hasError = compileTimeConstantChecker.checkConstantExpressionType(value, expression, context.expectedType); if (hasError) { IElementType elementType = expression.getNode().getElementType(); - return JetTypeInfo.create(components.expressionTypingUtils.getDefaultType(elementType), context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(components.expressionTypingUtils.getDefaultType(elementType), context); } } @@ -140,15 +140,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetExpression left = expression.getLeft(); JetTypeReference right = expression.getRight(); if (right == null) { - JetTypeInfo leftTypeInfo = facade.getTypeInfo(left, contextWithNoExpectedType); - return JetTypeInfo.create(null, leftTypeInfo.getDataFlowInfo()); + return facade.getTypeInfo(left, contextWithNoExpectedType).clearType(); } IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); boolean allowBareTypes = BARE_TYPES_ALLOWED.contains(operationType); TypeResolutionContext typeResolutionContext = new TypeResolutionContext(context.scope, context.trace, true, allowBareTypes); - PossiblyBareType possiblyBareTarget = components.expressionTypingServices.getTypeResolver().resolvePossiblyBareType(typeResolutionContext, right); + PossiblyBareType possiblyBareTarget = components.expressionTypingServices.getTypeResolver().resolvePossiblyBareType( + typeResolutionContext, right); if (operationType == JetTokens.COLON) { // We do not allow bare types on static assertions, because static assertions provide an expected type for their argument, @@ -158,26 +158,25 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType.replaceExpectedType(targetType)); checkBinaryWithTypeRHS(expression, context, targetType, typeInfo.getType()); - return DataFlowUtils.checkType(targetType, expression, context, typeInfo.getDataFlowInfo()); + return typeInfo.replaceType(targetType).checkType(expression, context); } JetTypeInfo typeInfo = facade.getTypeInfo(left, contextWithNoExpectedType); - DataFlowInfo dataFlowInfo = context.dataFlowInfo; JetType subjectType = typeInfo.getType(); JetType targetType = reconstructBareType(right, possiblyBareTarget, subjectType, context.trace); if (subjectType != null) { checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, subjectType); - dataFlowInfo = typeInfo.getDataFlowInfo(); + DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo(); if (operationType == AS_KEYWORD) { DataFlowValue value = createDataFlowValue(left, subjectType, context); - dataFlowInfo = dataFlowInfo.establishSubtyping(value, targetType); + typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.establishSubtyping(value, targetType)); } } JetType result = operationType == AS_SAFE ? TypeUtils.makeNullable(targetType) : targetType; - return DataFlowUtils.checkType(result, expression, context, dataFlowInfo); + return typeInfo.replaceType(result).checkType(expression, context); } private void checkBinaryWithTypeRHS( @@ -251,10 +250,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { break; case SUCCESS: result = resolutionResult.getReceiverParameterDescriptor().getType(); - context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result); + context.trace.recordType(expression.getInstanceReference(), result); break; } - return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(result, context, expression); } @Override @@ -276,9 +275,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { case SUCCESS: JetType result = checkPossiblyQualifiedSuper(expression, context, resolutionResult.getReceiverParameterDescriptor()); if (result != null) { - context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result); + context.trace.recordType(expression.getInstanceReference(), result); } - return DataFlowUtils.checkType(result, expression, context, context.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(result, context, expression); } throw new IllegalStateException("Unknown code: " + resolutionResult.getCode()); } @@ -288,7 +287,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (superTypeQualifier != null) { components.expressionTypingServices.getTypeResolver().resolveType(context.scope, superTypeQualifier, context.trace, true); } - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } private JetType checkPossiblyQualifiedSuper( @@ -366,7 +365,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace.report(SUPERCLASS_NOT_ACCESSIBLE_FROM_TRAIT.on(expression)); } } - context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result); + context.trace.recordType(expression.getInstanceReference(), result); context.trace.record(BindingContext.REFERENCE_TARGET, expression.getInstanceReference(), result.getConstructor().getDeclarationDescriptor()); } if (superTypeQualifier != null) { @@ -456,12 +455,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (type != null && !type.isError()) { JetType kClassType = components.reflectionTypes.getKClassType(Annotations.EMPTY, type); if (!kClassType.isError()) { - return JetTypeInfo.create(kClassType, c.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(kClassType, c); } c.trace.report(REFLECTION_TYPES_NOT_LOADED.on(expression.getDoubleColonTokenReference())); } - return JetTypeInfo.create(ErrorUtils.createErrorType("Unresolved class"), c.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(ErrorUtils.createErrorType("Unresolved class"), c); } @Nullable @@ -551,11 +550,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (callableReference.getReferencedName().isEmpty()) { c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference)); JetType errorType = ErrorUtils.createErrorType("Empty callable reference"); - return DataFlowUtils.checkType(errorType, expression, c, c.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(errorType, c, expression); } JetType result = getCallableReferenceType(expression, receiverType, c); - return DataFlowUtils.checkType(result, expression, c, c.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(result, c, expression); } @Override @@ -563,11 +562,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { DelegatingBindingTrace delegatingBindingTrace = context.trace.get(TRACE_DELTAS_CACHE, expression.getObjectDeclaration()); if (delegatingBindingTrace != null) { delegatingBindingTrace.addAllMyDataTo(context.trace); - JetType type = context.trace.get(EXPRESSION_TYPE, expression); - return DataFlowUtils.checkType(type, expression, context, context.dataFlowInfo); + JetType type = context.trace.getType(expression); + return TypeInfoFactoryPackage.createCheckedTypeInfo(type, context, expression); } final JetType[] result = new JetType[1]; - final TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve object literal expression", expression); + final TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(context.trace, + "trace to resolve object literal expression", expression); ObservableBindingTrace.RecordHandler handler = new ObservableBindingTrace.RecordHandler() { @Override @@ -582,8 +582,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } }); result[0] = defaultType; - if (!context.trace.get(PROCESSED, expression)) { - temporaryTrace.record(EXPRESSION_TYPE, expression, defaultType); + if (Boolean.FALSE.equals(context.trace.get(PROCESSED, expression))) { + temporaryTrace.recordType(expression, defaultType); temporaryTrace.record(PROCESSED, expression); } } @@ -604,7 +604,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { temporaryTrace.addAllMyDataTo(cloneDelta); context.trace.record(TRACE_DELTAS_CACHE, expression.getObjectDeclaration(), cloneDelta); temporaryTrace.commit(); - return DataFlowUtils.checkType(result[0], expression, context, context.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(result[0], context, expression); } @Nullable @@ -812,7 +812,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { : contextWithExpectedType.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE); JetExpression baseExpression = expression.getBaseExpression(); - if (baseExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo); + if (baseExpression == null) return TypeInfoFactoryPackage.createTypeInfo(context); JetSimpleNameExpression operationSign = expression.getOperationReference(); @@ -829,13 +829,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ExpressionReceiver receiver = new ExpressionReceiver(baseExpression, type); Call call = CallMaker.makeCall(receiver, expression); - DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo(); // Conventions for unary operations Name name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType); if (name == null) { context.trace.report(UNSUPPORTED.on(operationSign, "visitUnaryExpression")); - return JetTypeInfo.create(null, dataFlowInfo); + return typeInfo.clearType(); } // a[i]++/-- takes special treatment because it is actually let j = i, arr = a in arr.set(j, a.get(j).inc()) @@ -852,7 +851,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context, call, expression.getOperationReference(), name); if (!resolutionResults.isSuccess()) { - return JetTypeInfo.create(null, dataFlowInfo); + return typeInfo.clearType(); } // Computing the return type @@ -888,7 +887,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType); } - return DataFlowUtils.checkType(result, expression, contextWithExpectedType, dataFlowInfo); + return typeInfo.replaceType(result).checkType(expression, contextWithExpectedType); } @NotNull @@ -903,7 +902,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ArgumentTypeResolver.updateNumberType(expressionType, expression, context); } - return DataFlowUtils.checkType(expressionType, expression, context, context.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(expressionType, context, expression); } private JetTypeInfo visitExclExclExpression(@NotNull JetUnaryExpression expression, @NotNull ExpressionTypingContext context) { @@ -929,19 +928,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } else { DataFlowValue value = createDataFlowValue(baseExpression, baseType, context); - dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL); + baseTypeInfo = baseTypeInfo.replaceDataFlowInfo(dataFlowInfo.disequate(value, DataFlowValue.NULL)); } - // The call to checkType() is only needed here to execute additionalTypeCheckers, hence the NO_EXPECTED_TYPE JetType resultingType = TypeUtils.makeNotNullable(baseType); if (context.contextDependency == DEPENDENT) { - return JetTypeInfo.create(resultingType, dataFlowInfo); + return baseTypeInfo.replaceType(resultingType); } - return DataFlowUtils.checkType( - resultingType, - expression, - context.replaceExpectedType(NO_EXPECTED_TYPE), - dataFlowInfo - ); + + // 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)); } @Override @@ -958,13 +953,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { boolean isStatement ) { JetExpression baseExpression = expression.getBaseExpression(); - if (baseExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo); + if (baseExpression == null) return TypeInfoFactoryPackage.createTypeInfo(context); return facade.getTypeInfo(baseExpression, context, isStatement); } private static boolean isKnownToBeNotNull(JetExpression expression, ExpressionTypingContext context) { - JetType type = context.trace.get(EXPRESSION_TYPE, expression); + JetType type = context.trace.getType(expression); assert type != null : "This method is only supposed to be called when the type is not null"; return isKnownToBeNotNull(expression, type, context); } @@ -1073,7 +1068,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace.record(REFERENCE_TARGET, operationSign, components.builtIns.getIdentityEquals()); ensureNonemptyIntersectionOfOperandTypes(expression, context); // TODO : Check comparison pointlessness - result = JetTypeInfo.create(components.builtIns.getBooleanType(), context.dataFlowInfo); + result = TypeInfoFactoryPackage.createTypeInfo(components.builtIns.getBooleanType(), context); } else if (OperatorConventions.IN_OPERATIONS.contains(operationType)) { ValueArgument leftArgument = CallMaker.makeValueArgument(left, left != null ? left : operationSign); @@ -1084,7 +1079,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } else { context.trace.report(UNSUPPORTED.on(operationSign, "Unknown operation")); - result = JetTypeInfo.create(null, context.dataFlowInfo); + result = TypeInfoFactoryPackage.createTypeInfo(context); } CompileTimeConstant value = ConstantExpressionEvaluator.evaluate( expression, contextWithExpectedType.trace, contextWithExpectedType.expectedType @@ -1092,7 +1087,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (value != null) { return createCompileTimeConstantTypeInfo(value, expression, contextWithExpectedType); } - return DataFlowUtils.checkType(result, expression, contextWithExpectedType); + return result.checkType(expression, contextWithExpectedType); } private JetTypeInfo visitEquality( @@ -1102,29 +1097,27 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { final JetExpression left, final JetExpression right ) { - DataFlowInfo dataFlowInfo = context.dataFlowInfo; if (right == null || left == null) { ExpressionTypingUtils.getTypeInfoOrNullType(right, context, facade); ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade); - return JetTypeInfo.create(components.builtIns.getBooleanType(), dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(components.builtIns.getBooleanType(), context); } JetTypeInfo leftTypeInfo = getTypeInfoOrNullType(left, context, facade); - dataFlowInfo = leftTypeInfo.getDataFlowInfo(); + DataFlowInfo dataFlowInfo = leftTypeInfo.getDataFlowInfo(); ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo); JetTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithDataFlow); - dataFlowInfo = rightTypeInfo.getDataFlowInfo(); TemporaryBindingTrace traceInterpretingRightAsNullableAny = TemporaryBindingTrace.create( context.trace, "trace to resolve 'equals(Any?)' interpreting as of type Any? an expression:", right); - traceInterpretingRightAsNullableAny.record(EXPRESSION_TYPE, right, components.builtIns.getNullableAnyType()); + traceInterpretingRightAsNullableAny.recordType(right, components.builtIns.getNullableAnyType()); // Nothing? has no members, and `equals()` would be unresolved on it JetType leftType = leftTypeInfo.getType(); if (leftType != null && KotlinBuiltIns.isNothingOrNullableNothing(leftType)) { - traceInterpretingRightAsNullableAny.record(EXPRESSION_TYPE, left, components.builtIns.getNullableAnyType()); + traceInterpretingRightAsNullableAny.recordType(left, components.builtIns.getNullableAnyType()); } ExpressionTypingContext newContext = context.replaceBindingTrace(traceInterpretingRightAsNullableAny); @@ -1144,7 +1137,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public boolean accept(@Nullable WritableSlice slice, Object key) { // the type of the right (and sometimes left) expression isn't 'Any?' actually - if ((key == right || key == left) && slice == EXPRESSION_TYPE) return false; + if ((key == right || key == left) && slice == EXPRESSION_TYPE_INFO) return false; // a hack due to KT-678 // without this line an smartcast is reported on the receiver (if it was previously checked for not-null) @@ -1170,7 +1163,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace.report(EQUALS_MISSING.on(operationSign)); } } - return JetTypeInfo.create(components.builtIns.getBooleanType(), dataFlowInfo); + return rightTypeInfo.replaceType(components.builtIns.getBooleanType()); } @NotNull @@ -1180,7 +1173,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @NotNull JetSimpleNameExpression operationSign ) { JetTypeInfo typeInfo = getTypeInfoForBinaryCall(OperatorConventions.COMPARE_TO, context, expression); - DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo(); JetType compareToReturnType = typeInfo.getType(); JetType type = null; if (compareToReturnType != null && !compareToReturnType.isError()) { @@ -1191,7 +1183,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace.report(COMPARE_TO_TYPE_MISMATCH.on(operationSign, compareToReturnType)); } } - return JetTypeInfo.create(type, dataFlowInfo); + return typeInfo.replaceType(type); } @NotNull @@ -1216,7 +1208,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (right != null) { facade.getTypeInfo(right, contextForRightExpr); } - return JetTypeInfo.create(booleanType, dataFlowInfo); + return leftTypeInfo.replaceType(booleanType); } @NotNull @@ -1230,19 +1222,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (left == null || right == null) { getTypeInfoOrNullType(left, context, facade); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } Call call = createCallForSpecialConstruction(expression, expression.getOperationReference(), Lists.newArrayList(left, right)); ResolvedCall resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall( call, "Elvis", Lists.newArrayList("left", "right"), Lists.newArrayList(true, false), contextWithExpectedType, null); - TypeInfoWithJumpInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext()); + JetTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext()); assert leftTypeInfo != null : "Left expression was not processed: " + expression; JetType leftType = leftTypeInfo.getType(); if (leftType != null && isKnownToBeNotNull(left, leftType, context)) { context.trace.report(USELESS_ELVIS.on(left, leftType)); } - TypeInfoWithJumpInfo rightTypeInfo = BindingContextUtils.getRecordedTypeInfo(right, context.trace.getBindingContext()); + JetTypeInfo rightTypeInfo = BindingContextUtils.getRecordedTypeInfo(right, context.trace.getBindingContext()); assert rightTypeInfo != null : "Right expression was not processed: " + expression; boolean loopBreakContinuePossible = leftTypeInfo.getJumpOutPossible() || rightTypeInfo.getJumpOutPossible(); JetType rightType = rightTypeInfo.getType(); @@ -1253,7 +1245,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL); } JetType type = resolvedCall.getResultingDescriptor().getReturnType(); - if (type == null || rightType == null) return JetTypeInfo.create(null, dataFlowInfo); + if (type == null || rightType == null) return TypeInfoFactoryPackage.createTypeInfo(dataFlowInfo); // Sometimes return type for special call for elvis operator might be nullable, // but result is not nullable if the right type is not nullable @@ -1261,11 +1253,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { type = TypeUtils.makeNotNullable(type); } if (context.contextDependency == DEPENDENT) { - return JetTypeInfo.create(type, dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(type, dataFlowInfo); } - JetTypeInfo result = DataFlowUtils.checkType(type, expression, context, dataFlowInfo); - // If break or continue was possible, take condition check info as the jump info - return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), loopBreakContinuePossible, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkType(type, expression, context), + dataFlowInfo, + loopBreakContinuePossible, + context.dataFlowInfo); } @NotNull @@ -1280,10 +1273,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { ExpressionTypingContext contextWithNoExpectedType = context.replaceExpectedType(NO_EXPECTED_TYPE); if (right == null) { if (left != null) facade.getTypeInfo(left, contextWithNoExpectedType); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } - DataFlowInfo dataFlowInfo = facade.getTypeInfo(right, contextWithNoExpectedType).getDataFlowInfo(); + JetTypeInfo rightTypeInfo = facade.getTypeInfo(right, contextWithNoExpectedType); + DataFlowInfo dataFlowInfo = rightTypeInfo.getDataFlowInfo(); ExpressionReceiver receiver = safeGetExpressionReceiver(facade, right, contextWithNoExpectedType); ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo); @@ -1298,9 +1292,15 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (left != null) { dataFlowInfo = facade.getTypeInfo(left, contextWithDataFlow).getDataFlowInfo().and(dataFlowInfo); + rightTypeInfo = rightTypeInfo.replaceDataFlowInfo(dataFlowInfo); } - return JetTypeInfo.create(resolutionResult.isSuccess() ? components.builtIns.getBooleanType() : null, dataFlowInfo); + if (resolutionResult.isSuccess()) { + return rightTypeInfo.replaceType(components.builtIns.getBooleanType()); + } + else { + return rightTypeInfo.clearType(); + } } private void ensureNonemptyIntersectionOfOperandTypes(JetBinaryExpression expression, final ExpressionTypingContext context) { @@ -1350,13 +1350,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { private JetTypeInfo assignmentIsNotAnExpressionError(JetBinaryExpression expression, ExpressionTypingContext context) { facade.checkStatementType(expression, context); context.trace.report(ASSIGNMENT_IN_EXPRESSION_CONTEXT.on(expression)); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } @Override public JetTypeInfo visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, ExpressionTypingContext context) { - JetTypeInfo typeInfo = resolveArrayAccessGetMethod(expression, context); - return DataFlowUtils.checkType(typeInfo, expression, context); + return resolveArrayAccessGetMethod(expression, context).checkType(expression, context); } @NotNull @@ -1366,13 +1365,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @NotNull JetBinaryExpression binaryExpression ) { JetExpression left = binaryExpression.getLeft(); - DataFlowInfo dataFlowInfo = context.dataFlowInfo; + JetTypeInfo typeInfo; if (left != null) { //left here is a receiver, so it doesn't depend on expected type - dataFlowInfo = facade.getTypeInfo( - left, context.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)).getDataFlowInfo(); + typeInfo = facade.getTypeInfo(left, context.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)); + } else { + typeInfo = TypeInfoFactoryPackage.createTypeInfo(context); } - ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo); + ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()); OverloadResolutionResults resolutionResults; if (left != null) { @@ -1387,17 +1387,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } if (resolutionResults.isSingleResult()) { - dataFlowInfo = resolutionResults.getResultingCall().getDataFlowInfoForArguments().getResultInfo(); + typeInfo = typeInfo.replaceDataFlowInfo(resolutionResults.getResultingCall().getDataFlowInfoForArguments().getResultInfo()); } - return JetTypeInfo.create(OverloadResolutionResultsUtil.getResultingType(resolutionResults, context.contextDependency), - dataFlowInfo); + return typeInfo.replaceType(OverloadResolutionResultsUtil.getResultingType(resolutionResults, context.contextDependency)); } @Override public JetTypeInfo visitDeclaration(@NotNull JetDeclaration dcl, ExpressionTypingContext context) { context.trace.report(DECLARATION_IN_ILLEGAL_CONTEXT.on(dcl)); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } @Override @@ -1405,38 +1404,49 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (!JetPsiUtil.isLHSOfDot(expression)) { context.trace.report(PACKAGE_IS_NOT_AN_EXPRESSION.on(expression)); } - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } + private class StringTemplateVisitor extends JetVisitorVoid { + + final ExpressionTypingContext context; + + JetTypeInfo typeInfo; + + StringTemplateVisitor(ExpressionTypingContext context) { + this.context = context; + this.typeInfo = TypeInfoFactoryPackage.createTypeInfo(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) { - final ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); - final DataFlowInfo[] dataFlowInfo = new DataFlowInfo[] { context.dataFlowInfo }; + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); + StringTemplateVisitor visitor = new StringTemplateVisitor(context); for (JetStringTemplateEntry entry : expression.getEntries()) { - entry.accept(new JetVisitorVoid() { - - @Override - public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) { - JetExpression entryExpression = entry.getExpression(); - if (entryExpression != null) { - JetTypeInfo typeInfo = facade.getTypeInfo(entryExpression, context.replaceDataFlowInfo(dataFlowInfo[0])); - dataFlowInfo[0] = 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); - } - } - }); + entry.accept(visitor); } ConstantExpressionEvaluator.evaluate(expression, context.trace, contextWithExpectedType.expectedType); - return DataFlowUtils.checkType(components.builtIns.getStringType(), expression, contextWithExpectedType, dataFlowInfo[0]); + return visitor.typeInfo.replaceType(components.builtIns.getStringType()).checkType(expression, contextWithExpectedType); } @Override @@ -1450,7 +1460,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetExpression baseExpression = expression.getBaseExpression(); if (baseExpression == null) { - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } return facade.getTypeInfo(baseExpression, context, isStatement); } @@ -1458,7 +1468,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) { context.trace.report(UNSUPPORTED.on(element, getClass().getCanonicalName())); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } @NotNull @@ -1473,19 +1483,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @NotNull private JetTypeInfo resolveArrayAccessSpecialMethod(@NotNull JetArrayAccessExpression arrayAccessExpression, - @Nullable JetExpression rightHandSide, //only for 'set' method - @NotNull ExpressionTypingContext oldContext, - @NotNull BindingTrace traceForResolveResult, - boolean isGet) { + @Nullable JetExpression rightHandSide, //only for 'set' method + @NotNull ExpressionTypingContext oldContext, + @NotNull BindingTrace traceForResolveResult, + boolean isGet) { JetExpression arrayExpression = arrayAccessExpression.getArrayExpression(); - if (arrayExpression == null) return JetTypeInfo.create(null, oldContext.dataFlowInfo); + if (arrayExpression == null) return TypeInfoFactoryPackage.createTypeInfo(oldContext); + JetTypeInfo arrayTypeInfo = facade.safeGetTypeInfo(arrayExpression, oldContext.replaceExpectedType(NO_EXPECTED_TYPE) .replaceContextDependency(INDEPENDENT)); JetType arrayType = ExpressionTypingUtils.safeGetType(arrayTypeInfo); - DataFlowInfo dataFlowInfo = arrayTypeInfo.getDataFlowInfo(); - ExpressionTypingContext context = oldContext.replaceDataFlowInfo(dataFlowInfo); + ExpressionTypingContext context = oldContext.replaceDataFlowInfo(arrayTypeInfo.getDataFlowInfo()); ExpressionReceiver receiver = new ExpressionReceiver(arrayExpression, arrayType); if (!isGet) assert rightHandSide != null; @@ -1497,19 +1507,21 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { List indices = arrayAccessExpression.getIndexExpressions(); // The accumulated data flow info of all index expressions is saved on the last index + JetTypeInfo resultTypeInfo = arrayTypeInfo; if (!indices.isEmpty()) { - dataFlowInfo = facade.getTypeInfo(indices.get(indices.size() - 1), context).getDataFlowInfo(); + resultTypeInfo = facade.getTypeInfo(indices.get(indices.size() - 1), context); } if (!isGet) { - dataFlowInfo = facade.getTypeInfo(rightHandSide, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); + resultTypeInfo = facade.getTypeInfo(rightHandSide, context); } if (!functionResults.isSingleResult()) { traceForResolveResult.report(isGet ? NO_GET_METHOD.on(arrayAccessExpression) : NO_SET_METHOD.on(arrayAccessExpression)); - return JetTypeInfo.create(null, dataFlowInfo); + return resultTypeInfo.clearType(); } - traceForResolveResult.record(isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression, functionResults.getResultingCall()); - return JetTypeInfo.create(functionResults.getResultingDescriptor().getReturnType(), dataFlowInfo); + traceForResolveResult.record(isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression, + functionResults.getResultingCall()); + return resultTypeInfo.replaceType(functionResults.getResultingDescriptor().getReturnType()); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java index 0cdfa3a2f1a..763fd14cdba 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingUtils.java @@ -248,7 +248,7 @@ public class ControlStructureTypingUtils { @NotNull /*package*/ static TracingStrategy createTracingForSpecialConstruction( final @NotNull Call call, - final @NotNull String constructionName, + @NotNull String constructionName, final @NotNull ExpressionTypingContext context ) { class CheckTypeContext { 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 ac1e13d52d9..4aaf6e79165 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -22,11 +22,9 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.JetNodeTypes; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.diagnostics.Errors; -import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; @@ -43,6 +41,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver; import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.checker.JetTypeChecker; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import java.util.ArrayList; import java.util.Collections; @@ -104,15 +103,19 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (elseBranch == null) { if (thenBranch != null) { - TypeInfoWithJumpInfo result = getTypeInfoWhenOnlyOneBranchIsPresent( + JetTypeInfo result = getTypeInfoWhenOnlyOneBranchIsPresent( thenBranch, thenScope, thenInfo, elseInfo, contextWithExpectedType, ifExpression, isStatement); // If jump was possible, take condition check info as the jump info return result.getJumpOutPossible() ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo) : result; } - return DataFlowUtils.checkImplicitCast(components.builtIns.getUnitType(), ifExpression, contextWithExpectedType, - isStatement, thenInfo.or(elseInfo)); + return TypeInfoFactoryPackage.createTypeInfo(DataFlowUtils.checkImplicitCast( + components.builtIns.getUnitType(), ifExpression, + contextWithExpectedType, isStatement + ), + thenInfo.or(elseInfo) + ); } if (thenBranch == null) { return getTypeInfoWhenOnlyOneBranchIsPresent( @@ -130,8 +133,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { contextWithExpectedType, dataFlowInfoForArguments); BindingContext bindingContext = context.trace.getBindingContext(); - TypeInfoWithJumpInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext); - TypeInfoWithJumpInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext); + JetTypeInfo thenTypeInfo = BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext); + JetTypeInfo elseTypeInfo = BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext); assert thenTypeInfo != null : "'Then' branch of if expression was not processed: " + ifExpression; assert elseTypeInfo != null : "'Else' branch of if expression was not processed: " + ifExpression; boolean loopBreakContinuePossible = thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible(); @@ -159,13 +162,14 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } JetType resultType = resolvedCall.getResultingDescriptor().getReturnType(); - JetTypeInfo result = DataFlowUtils.checkImplicitCast(resultType, ifExpression, contextWithExpectedType, isStatement, resultDataFlowInfo); // If break or continue was possible, take condition check info as the jump info - return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), loopBreakContinuePossible, conditionDataFlowInfo); + return TypeInfoFactoryPackage + .createTypeInfo(DataFlowUtils.checkImplicitCast(resultType, ifExpression, contextWithExpectedType, isStatement), + resultDataFlowInfo, loopBreakContinuePossible, conditionDataFlowInfo); } @NotNull - private TypeInfoWithJumpInfo getTypeInfoWhenOnlyOneBranchIsPresent( + private JetTypeInfo getTypeInfoWhenOnlyOneBranchIsPresent( @NotNull JetExpression presentBranch, @NotNull WritableScopeImpl presentScope, @NotNull DataFlowInfo presentInfo, @@ -176,7 +180,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { ) { ExpressionTypingContext newContext = context.replaceDataFlowInfo(presentInfo).replaceExpectedType(NO_EXPECTED_TYPE) .replaceContextDependency(INDEPENDENT); - TypeInfoWithJumpInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( + JetTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( presentScope, Collections.singletonList(presentBranch), CoercionStrategy.NO_COERCION, newContext); JetType type = typeInfo.getType(); DataFlowInfo dataFlowInfo; @@ -185,9 +189,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } else { dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo); } - JetType typeForIfExpression = DataFlowUtils.checkType(components.builtIns.getUnitType(), ifExpression, context); - JetTypeInfo result = DataFlowUtils.checkImplicitCast(typeForIfExpression, ifExpression, context, isStatement, dataFlowInfo); - return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), typeInfo.getJumpOutPossible(), typeInfo.getJumpFlowInfo()); + return typeInfo.replaceType(components.builtIns.getUnitType()).checkType(ifExpression, context). + checkImplicitCast(ifExpression, context, isStatement).replaceDataFlowInfo(dataFlowInfo); } @Override @@ -211,13 +214,15 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { DataFlowInfo dataFlowInfo = checkCondition(context.scope, condition, context); JetExpression body = expression.getBody(); - TypeInfoWithJumpInfo bodyTypeInfo = null; + JetTypeInfo bodyTypeInfo; + DataFlowInfo conditionInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo); if (body != null) { WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in while's condition"); - DataFlowInfo conditionInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo); bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( scopeToExtend, Collections.singletonList(body), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(conditionInfo)); + } else { + bodyTypeInfo = TypeInfoFactoryPackage.createTypeInfo(conditionInfo); } // Condition is false at this point only if there is no jumps outside @@ -229,12 +234,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { // In this case we must record data flow information at the nearest break / continue and // .and it with entrance data flow information, because while body until break is executed at least once in this case // See KT-6284 - if (bodyTypeInfo != null && JetPsiUtil.isTrueConstant(condition)) { + if (body != null && JetPsiUtil.isTrueConstant(condition)) { // We should take data flow info from the first jump point, // but without affecting changing variables dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo())); } - return DataFlowUtils.checkType(components.builtIns.getUnitType(), expression, contextWithExpectedType, dataFlowInfo); + return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo( + dataFlowInfo); } private boolean containsJumpOutOfLoop(final JetLoopExpression loopExpression, final ExpressionTypingContext context) { @@ -296,7 +302,7 @@ 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 - TypeInfoWithJumpInfo bodyTypeInfo = null; + JetTypeInfo bodyTypeInfo; if (body instanceof JetFunctionLiteralExpression) { JetFunctionLiteralExpression function = (JetFunctionLiteralExpression) body; JetFunctionLiteral functionLiteral = function.getFunctionLiteral(); @@ -308,7 +314,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { context.trace.record(BindingContext.BLOCK, function); } else { - facade.getTypeInfo(body, context.replaceScope(context.scope)); + bodyTypeInfo = facade.getTypeInfo(body, context.replaceScope(context.scope)); } } else if (body != null) { @@ -324,6 +330,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( writableScope, block, CoercionStrategy.NO_COERCION, context); } + else { + bodyTypeInfo = TypeInfoFactoryPackage.createTypeInfo(context); + } JetExpression condition = expression.getCondition(); DataFlowInfo conditionDataFlowInfo = checkCondition(conditionScope, condition, context); DataFlowInfo dataFlowInfo; @@ -337,12 +346,13 @@ 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 - if (bodyTypeInfo != null) { + 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 DataFlowUtils.checkType(components.builtIns.getUnitType(), expression, contextWithExpectedType, dataFlowInfo); + return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo( + dataFlowInfo); } @Override @@ -361,14 +371,17 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { JetExpression loopRange = expression.getLoopRange(); JetType expectedParameterType = null; - DataFlowInfo dataFlowInfo = context.dataFlowInfo; + JetTypeInfo loopRangeInfo; if (loopRange != null) { ExpressionReceiver loopRangeReceiver = getExpressionReceiver(facade, loopRange, context.replaceScope(context.scope)); - dataFlowInfo = facade.getTypeInfo(loopRange, context).getDataFlowInfo(); + loopRangeInfo = facade.getTypeInfo(loopRange, context); if (loopRangeReceiver != null) { expectedParameterType = components.forLoopConventionsChecker.checkIterableConvention(loopRangeReceiver, context); } } + else { + loopRangeInfo = TypeInfoFactoryPackage.createTypeInfo(context); + } WritableScope loopScope = newWritableScopeImpl(context, "Scope with for-loop index"); @@ -389,12 +402,17 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } JetExpression body = expression.getBody(); + JetTypeInfo bodyTypeInfo; if (body != null) { - components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(loopScope, Collections.singletonList(body), - CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(dataFlowInfo)); + bodyTypeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(loopScope, Collections.singletonList(body), + CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo())); + } + else { + bodyTypeInfo = loopRangeInfo; } - return DataFlowUtils.checkType(components.builtIns.getUnitType(), expression, contextWithExpectedType, dataFlowInfo); + return bodyTypeInfo.replaceType(components.builtIns.getUnitType()).checkType(expression, contextWithExpectedType).replaceDataFlowInfo( + loopRangeInfo.getDataFlowInfo()); } private VariableDescriptor createLoopParameterDescriptor( @@ -462,10 +480,10 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } } - DataFlowInfo dataFlowInfo = context.dataFlowInfo; + JetTypeInfo result = TypeInfoFactoryPackage.createTypeInfo(context); if (finallyBlock != null) { - dataFlowInfo = facade.getTypeInfo(finallyBlock.getFinalExpression(), - context.replaceExpectedType(NO_EXPECTED_TYPE)).getDataFlowInfo(); + result = facade.getTypeInfo(finallyBlock.getFinalExpression(), + context.replaceExpectedType(NO_EXPECTED_TYPE)); } JetType type = facade.getTypeInfo(tryBlock, context).getType(); @@ -473,10 +491,10 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { types.add(type); } if (types.isEmpty()) { - return JetTypeInfo.create(null, dataFlowInfo); + return result.clearType(); } else { - return JetTypeInfo.create(CommonSupertypes.commonSupertype(types), dataFlowInfo); + return result.replaceType(CommonSupertypes.commonSupertype(types)); } } @@ -488,7 +506,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { facade.getTypeInfo(thrownExpression, context .replaceExpectedType(throwableType).replaceScope(context.scope).replaceContextDependency(INDEPENDENT)); } - return DataFlowUtils.checkType(components.builtIns.getNothingType(), expression, context, context.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression); } @Override @@ -556,7 +574,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType)); } } - return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo); + return TypeInfoFactoryPackage.createCheckedTypeInfo(resultType, context, expression); } private static boolean isClassInitializer(@NotNull Pair containingFunInfo) { @@ -565,17 +583,17 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } @Override - public TypeInfoWithJumpInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext context) { + public JetTypeInfo visitBreakExpression(@NotNull JetBreakExpression expression, ExpressionTypingContext context) { LabelResolver.INSTANCE.resolveControlLabel(expression, context); - JetTypeInfo result = DataFlowUtils.checkType(components.builtIns.getNothingType(), expression, context, context.dataFlowInfo); - return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), true, result.getDataFlowInfo()); + return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression). + replaceJumpOutPossible(true); } @Override - public TypeInfoWithJumpInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext context) { + public JetTypeInfo visitContinueExpression(@NotNull JetContinueExpression expression, ExpressionTypingContext context) { LabelResolver.INSTANCE.resolveControlLabel(expression, context); - JetTypeInfo result = DataFlowUtils.checkType(components.builtIns.getNothingType(), expression, context, context.dataFlowInfo); - return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), true, result.getDataFlowInfo()); + return TypeInfoFactoryPackage.createCheckedTypeInfo(components.builtIns.getNothingType(), context, expression). + replaceJumpOutPossible(true); } @NotNull 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 106117e2822..951b2517797 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowUtils.java @@ -37,10 +37,10 @@ import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.constants.evaluate.EvaluatePackage; import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.JetTypeInfo; import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypesPackage; import org.jetbrains.kotlin.types.checker.JetTypeChecker; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import java.util.Collection; @@ -92,9 +92,9 @@ public class DataFlowUtils { JetExpression right = expression.getRight(); if (right == null) return; - JetType lhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, left); + JetType lhsType = context.trace.getBindingContext().getType(left); if (lhsType == null) return; - JetType rhsType = context.trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, right); + JetType rhsType = context.trace.getBindingContext().getType(right); if (rhsType == null) return; DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, lhsType, context); @@ -144,23 +144,9 @@ public class DataFlowUtils { return context.dataFlowInfo.and(result.get()); } - @NotNull - public static JetTypeInfo checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context, @NotNull DataFlowInfo dataFlowInfo) { - return JetTypeInfo.create(checkType(expressionType, expression, context), dataFlowInfo); - } - - @NotNull - public static JetTypeInfo checkType(@NotNull JetTypeInfo typeInfo, @NotNull JetExpression expression, @NotNull ResolutionContext context) { - JetType type = checkType(typeInfo.getType(), expression, context); - if (type == typeInfo.getType()) { - return typeInfo; - } - return JetTypeInfo.create(type, typeInfo.getDataFlowInfo()); - } - @Nullable public static JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context) { - return checkType(expressionType, expression, context, (Ref) null); + return checkType(expressionType, expression, context, null); } @Nullable @@ -215,11 +201,6 @@ public class DataFlowUtils { } } - @NotNull - public static JetTypeInfo checkStatementType(@NotNull JetExpression expression, @NotNull ResolutionContext context, @NotNull DataFlowInfo dataFlowInfo) { - return JetTypeInfo.create(checkStatementType(expression, context), dataFlowInfo); - } - @Nullable public static JetType checkStatementType(@NotNull JetExpression expression, @NotNull ResolutionContext context) { if (!noExpectedType(context.expectedType) && !KotlinBuiltIns.isUnit(context.expectedType) && !context.expectedType.isError()) { @@ -229,13 +210,8 @@ public class DataFlowUtils { return KotlinBuiltIns.getInstance().getUnitType(); } - @NotNull - public static JetTypeInfo checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context, boolean isStatement, DataFlowInfo dataFlowInfo) { - return JetTypeInfo.create(checkImplicitCast(expressionType, expression, context, isStatement), dataFlowInfo); - } - @Nullable - public static JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context, boolean isStatement) { + public static JetType checkImplicitCast(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ResolutionContext context, boolean isStatement) { if (expressionType != null && context.expectedType == NO_EXPECTED_TYPE && context.contextDependency == INDEPENDENT && !isStatement && (KotlinBuiltIns.isUnit(expressionType) || KotlinBuiltIns.isAnyOrNullableAny(expressionType)) && !TypesPackage.isDynamic(expressionType)) { @@ -249,7 +225,7 @@ public class DataFlowUtils { facade.checkStatementType( expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)); context.trace.report(EXPRESSION_EXPECTED.on(expression, expression)); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingFacade.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingFacade.java index 3ec4b318734..f9456603b17 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingFacade.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingFacade.java @@ -17,9 +17,7 @@ package org.jetbrains.kotlin.types.expressions; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.psi.JetExpression; -import org.jetbrains.kotlin.types.JetTypeInfo; public interface ExpressionTypingFacade { @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingInternals.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingInternals.java index f74d66372ac..351581d427e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingInternals.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingInternals.java @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.types.expressions; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.types.JetTypeInfo; /*package*/ interface ExpressionTypingInternals extends ExpressionTypingFacade { @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java index a8f278c451d..581d1a6d7de 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingServices.java @@ -44,7 +44,7 @@ import org.jetbrains.kotlin.resolve.scopes.WritableScope; import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl; import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.JetTypeInfo; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import javax.inject.Inject; import java.util.Iterator; @@ -262,7 +262,7 @@ public class ExpressionTypingServices { JetTypeInfo r; if (block.isEmpty()) { - r = DataFlowUtils.checkType(builtIns.getUnitType(), expression, context, context.dataFlowInfo); + r = TypeInfoFactoryPackage.createCheckedTypeInfo(builtIns.getUnitType(), context, expression); } else { r = getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, @@ -308,20 +308,20 @@ public class ExpressionTypingServices { * Determines block returned type and data flow information at the end of the block AND * at the nearest jump point from the block beginning. */ - /*package*/ TypeInfoWithJumpInfo getBlockReturnedTypeWithWritableScope( + /*package*/ JetTypeInfo getBlockReturnedTypeWithWritableScope( @NotNull WritableScope scope, @NotNull List block, @NotNull CoercionStrategy coercionStrategyForLastExpression, @NotNull ExpressionTypingContext context ) { if (block.isEmpty()) { - return new TypeInfoWithJumpInfo(builtIns.getUnitType(), context.dataFlowInfo, false, context.dataFlowInfo); + return new JetTypeInfo(builtIns.getUnitType(), context.dataFlowInfo, false, context.dataFlowInfo); } ExpressionTypingInternals blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(expressionTypingComponents, scope); ExpressionTypingContext newContext = context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE); - JetTypeInfo result = JetTypeInfo.create(null, context.dataFlowInfo); + JetTypeInfo result = TypeInfoFactoryPackage.createTypeInfo(context); // Jump point data flow info DataFlowInfo beforeJumpInfo = newContext.dataFlowInfo; boolean jumpOutPossible = false; @@ -344,14 +344,8 @@ public class ExpressionTypingServices { DataFlowInfo newDataFlowInfo = result.getDataFlowInfo(); // If jump is not possible, we take new data flow info before jump if (!jumpOutPossible) { - if (result instanceof TypeInfoWithJumpInfo) { - TypeInfoWithJumpInfo jumpTypeInfo = (TypeInfoWithJumpInfo) result; - beforeJumpInfo = jumpTypeInfo.getJumpFlowInfo(); - jumpOutPossible = jumpTypeInfo.getJumpOutPossible(); - } - else { - beforeJumpInfo = newDataFlowInfo; - } + beforeJumpInfo = result.getJumpFlowInfo(); + jumpOutPossible = result.getJumpOutPossible(); } if (newDataFlowInfo != context.dataFlowInfo) { newContext = newContext.replaceDataFlowInfo(newDataFlowInfo); @@ -359,7 +353,7 @@ public class ExpressionTypingServices { } blockLevelVisitor = ExpressionTypingVisitorDispatcher.createForBlock(expressionTypingComponents, scope); } - return new TypeInfoWithJumpInfo(result.getType(), result.getDataFlowInfo(), jumpOutPossible, beforeJumpInfo); + return result.replaceJumpOutPossible(jumpOutPossible).replaceJumpFlowInfo(beforeJumpInfo); } private JetTypeInfo getTypeOfLastExpressionInBlock( @@ -397,7 +391,7 @@ public class ExpressionTypingServices { if (mightBeUnit) { // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and assignments assert result.getType() == null || KotlinBuiltIns.isUnit(result.getType()); - result = JetTypeInfo.create(builtIns.getUnitType(), context.dataFlowInfo); + result = result.replaceType(builtIns.getUnitType()).replaceDataFlowInfo(context.dataFlowInfo); } } return result; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java index aabdf737744..07e2ccaf671 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingUtils.java @@ -45,9 +45,9 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.JetTypeInfo; import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.checker.JetTypeChecker; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; import java.util.ArrayList; @@ -192,7 +192,7 @@ public class ExpressionTypingUtils { @NotNull JetType argumentType ) { JetExpression fakeExpression = JetPsiFactory(project).createExpression(argumentName); - trace.record(EXPRESSION_TYPE, fakeExpression, argumentType); + trace.recordType(fakeExpression, argumentType); trace.record(PROCESSED, fakeExpression); return fakeExpression; } @@ -336,7 +336,7 @@ public class ExpressionTypingUtils { ) { return expression != null ? facade.getTypeInfo(expression, context) - : JetTypeInfo.create(null, context.dataFlowInfo); + : TypeInfoFactoryPackage.createTypeInfo(context); } @SuppressWarnings("SuspiciousMethodCalls") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitor.java index 2d3d89693dc..a3677c466e3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitor.java @@ -18,7 +18,6 @@ package org.jetbrains.kotlin.types.expressions; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.psi.JetVisitor; -import org.jetbrains.kotlin.types.JetTypeInfo; /*package*/ abstract class ExpressionTypingVisitor extends JetVisitor { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java index 31dc9954165..19ea2c2a5d1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java @@ -29,7 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.WritableScope; import org.jetbrains.kotlin.types.DeferredType; import org.jetbrains.kotlin.types.ErrorUtils; import org.jetbrains.kotlin.types.JetType; -import org.jetbrains.kotlin.types.JetTypeInfo; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException; import org.jetbrains.kotlin.utils.KotlinFrontEndException; @@ -99,7 +99,8 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor visitor) { + static private JetTypeInfo getTypeInfo(@NotNull JetExpression expression, ExpressionTypingContext context, JetVisitor visitor) { try { JetTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext()); if (recordedTypeInfo != null) { @@ -140,34 +141,19 @@ public class ExpressionTypingVisitorDispatcher extends JetVisitor ambiguity OverloadResolutionResults ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity(assignmentOperationDescriptors, binaryOperationDescriptors); @@ -300,7 +303,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito for (ResolvedCall resolvedCall : ambiguityResolutionResults.getResultingCalls()) { descriptors.add(resolvedCall.getResultingDescriptor()); } - dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); + rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo())); context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors); } else if (assignmentOperationType != null && (assignmentOperationDescriptors.isSuccess() || !binaryOperationDescriptors.isSuccess())) { @@ -319,12 +322,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito context.trace, "trace to resolve array set method for assignment", expression)); basic.resolveArrayAccessSetMethod((JetArrayAccessExpression) left, right, contextForResolve, context.trace); } - dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); - DataFlowUtils.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(dataFlowInfo)); + rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(leftInfo.getDataFlowInfo())); + DataFlowUtils.checkType(binaryOperationType, expression, context.replaceExpectedType(leftType).replaceDataFlowInfo(rightInfo.getDataFlowInfo())); basic.checkLValue(context.trace, context, leftOperand, right); } temporary.commit(); - return JetTypeInfo.create(checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); + return rightInfo.replaceType(checkAssignmentType(type, expression, contextWithExpectedType)); } @NotNull @@ -336,30 +339,33 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito JetExpression right = expression.getRight(); if (left instanceof JetArrayAccessExpression) { JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; - if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo); + if (right == null) return TypeInfoFactoryPackage.createTypeInfo(context); JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace); basic.checkLValue(context.trace, context, arrayAccessExpression, right); - return JetTypeInfo.create(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType), - typeInfo.getDataFlowInfo()); + return typeInfo.replaceType(checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType)); } JetTypeInfo leftInfo = ExpressionTypingUtils.getTypeInfoOrNullType(left, context, facade); JetType leftType = leftInfo.getType(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); + JetTypeInfo rightInfo; if (right != null) { - JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType)); + rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType)); dataFlowInfo = rightInfo.getDataFlowInfo(); JetType rightType = rightInfo.getType(); if (left != null && leftType != null && rightType != null) { DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, leftType, context); DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context); // We cannot say here anything new about rightValue except it has the same value as leftValue - dataFlowInfo = dataFlowInfo.assign(leftValue, rightValue); + rightInfo = rightInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue)); } } + else { + rightInfo = leftInfo; + } if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated basic.checkLValue(context.trace, context, leftOperand, right); } - return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo); + return rightInfo.replaceType(DataFlowUtils.checkStatementType(expression, contextWithExpectedType)); } @@ -371,7 +377,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito @Override public JetTypeInfo visitJetElement(@NotNull JetElement element, ExpressionTypingContext context) { context.trace.report(UNSUPPORTED.on(element, "in a block")); - return JetTypeInfo.create(null, context.dataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(context); } @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt index 219fbaf4214..25462096976 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/FunctionsTypingVisitor.kt @@ -31,7 +31,6 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.BindingContext.AUTO_CREATED_IT import org.jetbrains.kotlin.resolve.BindingContext.EXPECTED_RETURN_TYPE -import org.jetbrains.kotlin.resolve.BindingContext.EXPRESSION_TYPE import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.scopes.WritableScope import org.jetbrains.kotlin.resolve.source.toSourceElement @@ -41,6 +40,8 @@ import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE import org.jetbrains.kotlin.types.TypeUtils.noExpectedType import org.jetbrains.kotlin.types.checker.JetTypeChecker import org.jetbrains.kotlin.types.expressions.CoercionStrategy.COERCION_TO_UNIT +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createCheckedTypeInfo +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo import org.jetbrains.kotlin.utils.addIfNotNull public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) { @@ -99,10 +100,10 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express } if (isStatement) { - return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo) + return createTypeInfo(DataFlowUtils.checkStatementType(function, context), context) } else { - return DataFlowUtils.checkType(createFunctionType(functionDescriptor), function, context, context.dataFlowInfo) + return createCheckedTypeInfo(createFunctionType(functionDescriptor), context, function) } } @@ -138,10 +139,10 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express val resultType = createFunctionType(functionDescriptor)!! if (functionTypeExpected) { // all checks were done before - return JetTypeInfo.create(resultType, context.dataFlowInfo) + return createTypeInfo(resultType, context) } - return DataFlowUtils.checkType(resultType, expression, context, context.dataFlowInfo) + return createCheckedTypeInfo(resultType, context, expression) } private fun createFunctionDescriptor( @@ -197,7 +198,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express // This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions context.trace.record(EXPECTED_RETURN_TYPE, functionLiteral, expectedType) val typeOfBodyExpression = // Type-check the body - components.expressionTypingServices.getBlockReturnedType(functionLiteral.getBodyExpression(), COERCION_TO_UNIT, newContext).getType() + components.expressionTypingServices.getBlockReturnedType(functionLiteral.getBodyExpression(), COERCION_TO_UNIT, newContext).type return declaredReturnType ?: computeReturnTypeBasedOnReturnExpressions(functionLiteral, context, typeOfBodyExpression) } @@ -218,7 +219,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express } else { // the type should have been computed by getBlockReturnedType() above, but can be null, if returnExpression contains some error - returnedExpressionTypes.addIfNotNull(context.trace.get(EXPRESSION_TYPE, returnedExpression)) + returnedExpressionTypes.addIfNotNull(context.trace.getType(returnedExpression)) } } @@ -226,7 +227,7 @@ public class FunctionsTypingVisitor(facade: ExpressionTypingInternals) : Express for (returnExpression in returnExpressions) { val returnedExpression = returnExpression.getReturnedExpression() if (returnedExpression != null) { - val type = context.trace.get(EXPRESSION_TYPE, returnedExpression) + val type = context.trace.getType(returnedExpression) if (type == null || !KotlinBuiltIns.isUnit(type)) { context.trace.report(RETURN_TYPE_MISMATCH.on(returnedExpression, components.builtIns.getUnitType())) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt new file mode 100644 index 00000000000..67e49294403 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/JetTypeInfo.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.types.expressions + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +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 + +/** + * Stores simultaneously type of current expression together with data flow info + * and jump point data flow info, together with information about possible jump outside. For example: + * do { + * x!!.foo() + * if (bar()) break; + * y!!.gav() + * } while (bis()) + * At the end current data flow info is x != null && y != null, but jump data flow info is x != null only. + * Both break and continue are counted as possible jump outside of a loop, but return is not. + */ +/*package*/ open class JetTypeInfo( + val type: JetType?, + val dataFlowInfo: DataFlowInfo, + val jumpOutPossible: Boolean = false, + val jumpFlowInfo: DataFlowInfo = dataFlowInfo +) { + + 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) + + fun replaceJumpOutPossible(jumpOutPossible: Boolean) = + if (jumpOutPossible == this.jumpOutPossible) this else JetTypeInfo(type, dataFlowInfo, jumpOutPossible, jumpFlowInfo) + + 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) +} \ 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 b12b0b1123d..52c57491fa8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.calls.util.CallMaker; import org.jetbrains.kotlin.resolve.scopes.WritableScope; import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.checker.JetTypeChecker; +import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryPackage; import java.util.Collections; import java.util.Set; @@ -50,18 +51,18 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitIsExpression(@NotNull JetIsExpression expression, ExpressionTypingContext contextWithExpectedType) { - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency( + INDEPENDENT); JetExpression leftHandSide = expression.getLeftHandSide(); JetTypeInfo typeInfo = facade.safeGetTypeInfo(leftHandSide, context.replaceScope(context.scope)); JetType knownType = typeInfo.getType(); - DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo(); if (expression.getTypeReference() != null) { DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(leftHandSide, knownType, context); DataFlowInfo conditionInfo = checkTypeForIs(context, knownType, expression.getTypeReference(), dataFlowValue).thenInfo; - DataFlowInfo newDataFlowInfo = conditionInfo.and(dataFlowInfo); + DataFlowInfo newDataFlowInfo = conditionInfo.and(typeInfo.getDataFlowInfo()); context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo); } - return DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getBooleanType(), expression, contextWithExpectedType, dataFlowInfo); + return typeInfo.replaceType(KotlinBuiltIns.getInstance().getBooleanType()).checkType(expression, contextWithExpectedType); } @Override @@ -77,11 +78,13 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { JetExpression subjectExpression = expression.getSubjectExpression(); JetType subjectType; + boolean loopBreakContinuePossible = false; if (subjectExpression == null) { subjectType = ErrorUtils.createErrorType("Unknown type"); } else { JetTypeInfo typeInfo = facade.safeGetTypeInfo(subjectExpression, context); + loopBreakContinuePossible = typeInfo.getJumpOutPossible(); subjectType = typeInfo.getType(); context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo()); } @@ -107,6 +110,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { CoercionStrategy coercionStrategy = isStatement ? CoercionStrategy.COERCION_TO_UNIT : CoercionStrategy.NO_COERCION; JetTypeInfo typeInfo = components.expressionTypingServices.getBlockReturnedTypeWithWritableScope( scopeToExtend, Collections.singletonList(bodyExpression), coercionStrategy, newContext); + loopBreakContinuePossible |= typeInfo.getJumpOutPossible(); JetType type = typeInfo.getType(); if (type != null) { expressionTypes.add(type); @@ -124,10 +128,12 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { commonDataFlowInfo = context.dataFlowInfo; } - if (!expressionTypes.isEmpty()) { - return DataFlowUtils.checkImplicitCast(CommonSupertypes.commonSupertype(expressionTypes), expression, contextWithExpectedType, isStatement, commonDataFlowInfo); - } - return JetTypeInfo.create(null, commonDataFlowInfo); + return TypeInfoFactoryPackage.createTypeInfo(expressionTypes.isEmpty() ? null : DataFlowUtils.checkImplicitCast( + CommonSupertypes.commonSupertype(expressionTypes), expression, + contextWithExpectedType, isStatement), + commonDataFlowInfo, + loopBreakContinuePossible, + contextWithExpectedType.dataFlowInfo); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt new file mode 100644 index 00000000000..91b16fecd9d --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoFactory.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.types.expressions.typeInfoFactory + +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.JetTypeInfo + +/** + * Functions in this file are intended to create type info instances in different circumstances + */ + +public fun createTypeInfo(type: JetType?): JetTypeInfo = createTypeInfo(type, DataFlowInfo.EMPTY) + +public fun createTypeInfo(dataFlowInfo: DataFlowInfo): JetTypeInfo = JetTypeInfo(null, dataFlowInfo) + +public fun createTypeInfo(context: ResolutionContext<*>): JetTypeInfo = createTypeInfo(context.dataFlowInfo) + +public fun createTypeInfo(type: JetType?, dataFlowInfo: DataFlowInfo): JetTypeInfo = JetTypeInfo(type, dataFlowInfo) + +public fun createTypeInfo(type: JetType?, context: ResolutionContext<*>): JetTypeInfo = createTypeInfo(type, context.dataFlowInfo) + +public fun createTypeInfo(type: JetType?, dataFlowInfo: DataFlowInfo, jumpPossible: Boolean, jumpFlowInfo: DataFlowInfo): JetTypeInfo = + JetTypeInfo(type, dataFlowInfo, jumpPossible, jumpFlowInfo) + +public fun createCheckedTypeInfo(type: JetType?, context: ResolutionContext<*>, expression: JetExpression): JetTypeInfo = + createTypeInfo(type, context).checkType(expression, context) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoWithJumpInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoWithJumpInfo.kt deleted file mode 100644 index 2c628e59281..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/TypeInfoWithJumpInfo.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.types.expressions - -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo -import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.types.JetTypeInfo - -/** - * A local descendant of JetTypeInfo. Stores simultaneously current type with data flow info - * and jump point data flow info, together with information about possible jump outside. For example: - * do { - * x!!.foo() - * if (bar()) break; - * y!!.gav() - * } while (bis()) - * At the end current data flow info is x != null && y != null, but jump data flow info is x != null only. - * Both break and continue are counted as possible jump outside of a loop, but return is not. - */ -/*package*/ class TypeInfoWithJumpInfo( - type: JetType?, - dataFlowInfo: DataFlowInfo, - val jumpOutPossible: Boolean = false, - val jumpFlowInfo: DataFlowInfo = dataFlowInfo -) : JetTypeInfo(type, dataFlowInfo) { - - fun replaceType(type: JetType?) = TypeInfoWithJumpInfo(type, getDataFlowInfo(), jumpOutPossible, jumpFlowInfo) - - fun replaceJumpOutPossible(jumpOutPossible: Boolean) = TypeInfoWithJumpInfo(getType(), getDataFlowInfo(), jumpOutPossible, jumpFlowInfo) - - fun replaceJumpFlowInfo(jumpFlowInfo: DataFlowInfo) = TypeInfoWithJumpInfo(getType(), getDataFlowInfo(), jumpOutPossible, jumpFlowInfo) -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.kt new file mode 100644 index 00000000000..2f8a7167440 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.kt @@ -0,0 +1,11 @@ +public fun foo(x: String?, y: String?): Int { + while (true) { + val z = x ?: if (y == null) break else y + // z is not null in both branches + z.length() + // y is not null in both branches + y.length() + } + // y is null because of the break + return y.length() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.txt new file mode 100644 index 00000000000..74faaa4f9c5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.kt new file mode 100644 index 00000000000..975aa6da12e --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.kt @@ -0,0 +1,15 @@ +public fun foo(x: String?): Int { + var y: Any + @loop while (true) { + y = when (x) { + null -> break@loop + "abc" -> return 0 + "xyz" -> return 1 + else -> x.length() + } + // y is always Int after when + y: Int + } + // x is null because of the break + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.txt new file mode 100644 index 00000000000..cd85b07bb38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt new file mode 100644 index 00000000000..d8c26b3ecf8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt @@ -0,0 +1,12 @@ +fun bar(): Boolean { return true } + +public fun foo(x: String?): Int { + var y: Any + do { + y = "" + y = if (x == null) break else x + } while (bar()) + y.hashCode() + // x is null because of the break + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.txt new file mode 100644 index 00000000000..21db55461ca --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.txt @@ -0,0 +1,4 @@ +package + +internal fun bar(): kotlin.Boolean +public fun foo(/*0*/ x: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.kt new file mode 100644 index 00000000000..04fbcf20ece --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.kt @@ -0,0 +1,10 @@ +public fun foo(x: String?): Int { + var y: Any + while (true) { + y = if (x == null) break else x + } + // In future we can infer this initialization + y.hashCode() + // x is null because of the break + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.txt new file mode 100644 index 00000000000..cd85b07bb38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.kt new file mode 100644 index 00000000000..f49853906d2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.kt @@ -0,0 +1,10 @@ +public fun foo(x: String?): Int { + while (true) { + // After the check, smart cast should work + val y = if (x == null) break else x + // y is not null in both branches + y.length() + } + // x is null because of the break + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.txt new file mode 100644 index 00000000000..cd85b07bb38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.kt new file mode 100644 index 00000000000..a2b387ea0b4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.kt @@ -0,0 +1,11 @@ +public fun foo(x: String?, y: String?): Int { + while (true) { + val z = (if (y == null) break else x) ?: y + // z is not null in both branches + z.length() + // y is not null in both branches + y.length() + } + // y is null because of the break + return y.length() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.txt new file mode 100644 index 00000000000..74faaa4f9c5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.kt new file mode 100644 index 00000000000..e0aad11d31a --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.kt @@ -0,0 +1,20 @@ +fun bar(): Boolean { return true } + +public fun foo(x: String?): Int { + var y: Int? + y = 0 + @loop do { + y += when (x) { + null -> break@loop + "abc" -> return 0 + "xyz" -> return 1 + else -> x.length() + } + // y is always Int after when + y: Int + } while (bar()) + // y is always Int even here + y: Int + // x is null because of the break + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.txt new file mode 100644 index 00000000000..21db55461ca --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.txt @@ -0,0 +1,4 @@ +package + +internal fun bar(): kotlin.Boolean +public fun foo(/*0*/ x: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.kt new file mode 100644 index 00000000000..919e9e50e63 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.kt @@ -0,0 +1,12 @@ +public fun foo(x: String?): Int { + @loop while (true) { + when (x) { + null -> break@loop + "abc" -> return 0 + "xyz" -> return 1 + else -> x.length() + } + } + // x is null because of the break + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.txt new file mode 100644 index 00000000000..cd85b07bb38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.kt b/compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.kt new file mode 100644 index 00000000000..13779dcf763 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.kt @@ -0,0 +1,13 @@ +public fun foo(x: String?): Int { + @loop while (true) { + when (x) { + null -> return -1 + "abc" -> return 0 + "xyz" -> return 1 + else -> break@loop + } + } + // x is not null because of the break + // but we are not able to detect it + return x.length() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.txt b/compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.txt new file mode 100644 index 00000000000..cd85b07bb38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?): kotlin.Int diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 50c7a637edd..0924020d1c6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -11078,6 +11078,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts/loops"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("assignElvisIfBreakInsideWhileTrue.kt") + public void testAssignElvisIfBreakInsideWhileTrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/assignElvisIfBreakInsideWhileTrue.kt"); + doTest(fileName); + } + + @TestMetadata("assignWhenInsideWhileTrue.kt") + public void testAssignWhenInsideWhileTrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/assignWhenInsideWhileTrue.kt"); + doTest(fileName); + } + @TestMetadata("doWhile.kt") public void testDoWhile() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/doWhile.kt"); @@ -11174,6 +11186,24 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("ifBreakAssignInsideDoWhile.kt") + public void testIfBreakAssignInsideDoWhile() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideDoWhile.kt"); + doTest(fileName); + } + + @TestMetadata("ifBreakAssignInsideWhileTrue.kt") + public void testIfBreakAssignInsideWhileTrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakAssignInsideWhileTrue.kt"); + doTest(fileName); + } + + @TestMetadata("ifBreakExprInsideWhileTrue.kt") + public void testIfBreakExprInsideWhileTrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifBreakExprInsideWhileTrue.kt"); + doTest(fileName); + } + @TestMetadata("ifElseBlockInsideDoWhile.kt") public void testIfElseBlockInsideDoWhile() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/ifElseBlockInsideDoWhile.kt"); @@ -11186,6 +11216,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("leftElvisBreakInsideWhileTrue.kt") + public void testLeftElvisBreakInsideWhileTrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/leftElvisBreakInsideWhileTrue.kt"); + doTest(fileName); + } + @TestMetadata("nestedDoWhile.kt") public void testNestedDoWhile() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/nestedDoWhile.kt"); @@ -11228,12 +11264,30 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("plusAssignWhenInsideDoWhile.kt") + public void testPlusAssignWhenInsideDoWhile() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/plusAssignWhenInsideDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("useInsideDoWhile.kt") public void testUseInsideDoWhile() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/useInsideDoWhile.kt"); doTest(fileName); } + @TestMetadata("whenInsideWhileTrue.kt") + public void testWhenInsideWhileTrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/whenInsideWhileTrue.kt"); + doTest(fileName); + } + + @TestMetadata("whenReturnInsideWhileTrue.kt") + public void testWhenReturnInsideWhileTrue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/whenReturnInsideWhileTrue.kt"); + doTest(fileName); + } + @TestMetadata("whileInCondition.kt") public void testWhileInCondition() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/loops/whileInCondition.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java b/compiler/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java index 57b4f8a25f2..c3b8141483b 100644 --- a/compiler/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java +++ b/compiler/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java @@ -298,7 +298,7 @@ public abstract class ExpectedResolveData { PsiElement element = position.getElement(); JetExpression expression = getAncestorOfType(JetExpression.class, element); - JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); + JetType expressionType = bindingContext.getType(expression); TypeConstructor expectedTypeConstructor; if (typeName.startsWith(STANDARD_PREFIX)) { String name = typeName.substring(STANDARD_PREFIX.length()); diff --git a/compiler/tests/org/jetbrains/kotlin/test/JetTestUtils.java b/compiler/tests/org/jetbrains/kotlin/test/JetTestUtils.java index 5a45bed3e2e..a697c880a78 100644 --- a/compiler/tests/org/jetbrains/kotlin/test/JetTestUtils.java +++ b/compiler/tests/org/jetbrains/kotlin/test/JetTestUtils.java @@ -61,6 +61,7 @@ import org.jetbrains.kotlin.idea.JetLanguage; import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.platform.PlatformToKotlinClassMap; +import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; @@ -69,6 +70,8 @@ import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil; import org.jetbrains.kotlin.resolve.lazy.LazyResolveTestUtil; import org.jetbrains.kotlin.test.util.UtilPackage; +import org.jetbrains.kotlin.types.JetType; +import org.jetbrains.kotlin.types.expressions.JetTypeInfo; import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice; import org.jetbrains.kotlin.util.slicedMap.SlicedMap; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; @@ -141,6 +144,12 @@ public class JetTestUtils { public ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice) { return ImmutableMap.of(); } + + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + return DUMMY_TRACE.getType(expression); + } }; } @@ -166,6 +175,17 @@ public class JetTestUtils { return Collections.emptySet(); } + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + JetTypeInfo typeInfo = get(BindingContext.EXPRESSION_TYPE_INFO, expression); + return typeInfo != null ? typeInfo.getType() : null; + } + + @Override + public void recordType(@NotNull JetExpression expression, @Nullable JetType type) { + } + @Override public void report(@NotNull Diagnostic diagnostic) { if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) { @@ -202,6 +222,12 @@ public class JetTestUtils { public ImmutableMap getSliceContents(@NotNull ReadOnlySlice slice) { return ImmutableMap.of(); } + + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + return DUMMY_EXCEPTION_ON_ERROR_TRACE.getType(expression); + } }; } @@ -225,6 +251,16 @@ public class JetTestUtils { return Collections.emptySet(); } + @Nullable + @Override + public JetType getType(@NotNull JetExpression expression) { + return null; + } + + @Override + public void recordType(@NotNull JetExpression expression, @Nullable JetType type) { + } + @Override public void report(@NotNull Diagnostic diagnostic) { if (diagnostic.getSeverity() == Severity.ERROR) { diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index e506acb3279..d7e6927f485 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -96,7 +96,7 @@ public class ReferenceVariantsHelper( val expressionType = if (useRuntimeReceiverType) getQualifierRuntimeType(receiverExpression) else - context[BindingContext.EXPRESSION_TYPE, receiverExpression] + context.getType(receiverExpression) if (expressionType != null && !expressionType.isError()) { val receiverValue = ExpressionReceiver(receiverExpression, expressionType) val dataFlowInfo = context.getDataFlowInfo(expression) @@ -164,7 +164,7 @@ public class ReferenceVariantsHelper( val receiverData = getExplicitReceiverData(expression) if (receiverData != null) { val receiverExpression = receiverData.first - val expressionType = context[BindingContext.EXPRESSION_TYPE, receiverExpression] ?: return ReceiversData.Empty + val expressionType = context.getType(receiverExpression) ?: return ReceiversData.Empty return ReceiversData(listOf(ExpressionReceiver(receiverExpression, expressionType)), receiverData.second) } else { @@ -174,7 +174,7 @@ public class ReferenceVariantsHelper( } private fun getQualifierRuntimeType(receiver: JetExpression): JetType? { - val type = context[BindingContext.EXPRESSION_TYPE, receiver] + val type = context.getType(receiver) if (type != null && TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)) { val evaluator = receiver.getContainingFile().getCopyableUserData(JetCodeFragment.RUNTIME_TYPE_EVALUATOR) return evaluator?.invoke(receiver) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt index ea22b5f9dca..ae685cedf82 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/OperatorToFunctionIntention.kt @@ -127,7 +127,7 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention "$leftText.plus($rightText)" diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt index 6afc7df1981..f9887063005 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt @@ -139,7 +139,7 @@ class ExpectedInfos( val callOperationNode: ASTNode? if (parent is JetQualifiedExpression && callElement == parent.getSelectorExpression()) { val receiverExpression = parent.getReceiverExpression() - val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression] + val expressionType = bindingContext.getType(receiverExpression) val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] if (expressionType != null) { receiver = ExpressionReceiver(receiverExpression, expressionType) @@ -231,7 +231,7 @@ class ExpectedInfos( || operationToken == JetTokens.EQEQEQ || operationToken == JetTokens.EXCLEQEQEQ) { val otherOperand = if (expressionWithType == binaryExpression.getRight()) binaryExpression.getLeft() else binaryExpression.getRight() if (otherOperand != null) { - val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, otherOperand] ?: return null + val expressionType = bindingContext.getType(otherOperand) ?: return null return listOf(ExpectedInfo(expressionType, expectedNameFromExpression(otherOperand), null)) } } @@ -248,7 +248,7 @@ class ExpectedInfos( ifExpression.getElse() -> { val ifExpectedInfo = calculate(ifExpression) - val thenType = bindingContext[BindingContext.EXPRESSION_TYPE, ifExpression.getThen()] + val thenType = bindingContext.getType(ifExpression.getThen()) if (thenType != null) ifExpectedInfo?.filter { it.type.isSubtypeOf(thenType) } else @@ -265,7 +265,7 @@ class ExpectedInfos( val operationToken = binaryExpression.getOperationToken() if (operationToken == JetTokens.ELVIS && expressionWithType == binaryExpression.getRight()) { val leftExpression = binaryExpression.getLeft() ?: return null - val leftType = bindingContext[BindingContext.EXPRESSION_TYPE, leftExpression] + val leftType = bindingContext.getType(leftExpression) val leftTypeNotNullable = leftType?.makeNotNullable() val expectedInfos = calculate(binaryExpression) if (expectedInfos != null) { @@ -294,7 +294,7 @@ class ExpectedInfos( val whenExpression = entry.getParent() as JetWhenExpression val subject = whenExpression.getSubjectExpression() if (subject != null) { - val subjectType = bindingContext[BindingContext.EXPRESSION_TYPE, subject] ?: return null + val subjectType = bindingContext.getType(subject) ?: return null return listOf(ExpectedInfo(subjectType, null, null)) } else { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt index b4f43de2fe3..6c1e8499d86 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt @@ -298,7 +298,7 @@ class SmartCompletion( } } - val subjectType = bindingContext[BindingContext.EXPRESSION_TYPE, subject] ?: return setOf() + val subjectType = bindingContext.getType(subject) ?: return setOf() val classDescriptor = TypeUtils.getClassDescriptor(subjectType) if (classDescriptor != null && DescriptorUtils.isEnumClass(classDescriptor)) { val conditions = whenExpression.getEntries() @@ -410,7 +410,7 @@ class SmartCompletion( val operationToken = binaryExpression.getOperationToken() if (operationToken != JetTokens.IN_KEYWORD && operationToken != JetTokens.NOT_IN || expressionWithType != binaryExpression.getRight()) return null - val leftOperandType = bindingContext.get(BindingContext.EXPRESSION_TYPE, binaryExpression.getLeft()) ?: return null + val leftOperandType = bindingContext.getType(binaryExpression.getLeft()) ?: return null val scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expressionWithType) val detector = TypesWithContainsDetector(scope, leftOperandType, project, moduleDescriptor) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index ab850cbd477..af02a1cdd73 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -122,7 +122,7 @@ public class KotlinIndicesHelper( if (receiverPair != null) { val (receiverExpression, callType) = receiverPair - val expressionType = bindingContext[BindingContext.EXPRESSION_TYPE, receiverExpression] + val expressionType = bindingContext.getType(receiverExpression) if (expressionType == null || expressionType.isError()) return emptyList() val receiverValue = ExpressionReceiver(receiverExpression, expressionType) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/SmartCastCalculator.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/SmartCastCalculator.kt index e7d34fbfd3f..4f0ffc01eed 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/SmartCastCalculator.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/SmartCastCalculator.kt @@ -65,7 +65,7 @@ class SmartCastCalculator(val bindingContext: BindingContext, val containingDecl val dataFlowValueToVariable: (DataFlowValue) -> VariableDescriptor? if (receiver != null) { - val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver] ?: return ProcessDataFlowInfoResult() + val receiverType = bindingContext.getType(receiver) ?: return ProcessDataFlowInfoResult() val receiverId = DataFlowValueFactory.createDataFlowValue(receiver, receiverType, bindingContext, containingDeclarationOrModule).getId() dataFlowValueToVariable = { value -> val id = value.getId() diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt index 5210261e16b..66ea02ace7b 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/descriptorUtils.kt @@ -35,7 +35,7 @@ fun DeclarationDescriptorWithVisibility.isVisible( if (bindingContext == null || element == null) return false val receiver = element.getReceiverExpression() - val type = receiver?.let { bindingContext.get(BindingContext.EXPRESSION_TYPE, it) } + val type = receiver?.let { bindingContext.getType(it) } val explicitReceiver = type?.let { ExpressionReceiver(receiver, it) } if (explicitReceiver != null) { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/refactoring/JetNameSuggester.java b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/refactoring/JetNameSuggester.java index d662f612a77..5d4c7659dce 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/refactoring/JetNameSuggester.java +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/refactoring/JetNameSuggester.java @@ -69,7 +69,7 @@ public class JetNameSuggester { ArrayList result = new ArrayList(); BindingContext bindingContext = ResolvePackage.analyze(expression, BodyResolveMode.FULL); - JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); + JetType jetType = bindingContext.getType(expression); if (jetType != null) { addNamesForType(result, jetType, validator); } diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/ShowExpressionTypeAction.java b/idea/src/org/jetbrains/kotlin/idea/actions/ShowExpressionTypeAction.java index 5078ba265be..22dfde881c4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/ShowExpressionTypeAction.java +++ b/idea/src/org/jetbrains/kotlin/idea/actions/ShowExpressionTypeAction.java @@ -50,7 +50,7 @@ public class ShowExpressionTypeAction extends AnAction { else { int offset = editor.getCaretModel().getOffset(); expression = PsiTreeUtil.getParentOfType(psiFile.findElementAt(offset), JetExpression.class); - while (expression != null && bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) == null) { + while (expression != null && bindingContext.getType(expression) == null) { expression = PsiTreeUtil.getParentOfType(expression, JetExpression.class); } if (expression != null) { @@ -59,7 +59,7 @@ public class ShowExpressionTypeAction extends AnAction { } } if (expression != null) { - JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); + JetType type = bindingContext.getType(expression); if (type != null) { HintManager.getInstance().showInformationHint(editor, "" + DescriptorRenderer.HTML.renderType(type) + ""); } diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/internal/CheckPartialBodyResolveAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/internal/CheckPartialBodyResolveAction.kt index 05aa3e04432..98f48023d62 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/internal/CheckPartialBodyResolveAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/internal/CheckPartialBodyResolveAction.kt @@ -135,7 +135,7 @@ public class CheckPartialBodyResolveAction : AnAction() { builder.append(" resolves to ${target?.presentation()}") } - val type = bindingContext[BindingContext.EXPRESSION_TYPE, expression] + val type = bindingContext.getType(expression) if (type != null) { builder.append(" has type ${type.presentation()}") } diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt index 7daa38c6fa6..570c89e9a1f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/internal/FindImplicitNothingAction.kt @@ -77,7 +77,7 @@ public class FindImplicitNothingAction : AnAction() { try { val bindingContext = resolutionFacade.analyze(expression) - val type = bindingContext[BindingContext.EXPRESSION_TYPE, expression] ?: return + val type = bindingContext.getType(expression) ?: return if (KotlinBuiltIns.isNothing(type) && !expression.hasExplicitNothing(bindingContext)) { //TODO: what about nullable Nothing? found.add(expression) } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinExpressionSurrounder.java b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinExpressionSurrounder.java index 30e8e457a28..39972fca279 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinExpressionSurrounder.java +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinExpressionSurrounder.java @@ -44,7 +44,7 @@ public abstract class KotlinExpressionSurrounder implements Surrounder { if (expression instanceof JetCallExpression && expression.getParent() instanceof JetQualifiedExpression) { return false; } - JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).get(BindingContext.EXPRESSION_TYPE, expression); + JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).getType(expression); if (type == null || type.equals(KotlinBuiltIns.getInstance().getUnitType())) { return false; } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinNotSurrounder.java b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinNotSurrounder.java index 588c8dfd4b1..2ec84fa858b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinNotSurrounder.java +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinNotSurrounder.java @@ -42,7 +42,7 @@ public class KotlinNotSurrounder extends KotlinExpressionSurrounder { @Override public boolean isApplicable(@NotNull JetExpression expression) { - JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).get(BindingContext.EXPRESSION_TYPE, expression); + JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).getType(expression); return KotlinBuiltIns.getInstance().getBooleanType().equals(type); } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinRuntimeTypeCastSurrounder.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinRuntimeTypeCastSurrounder.kt index 08b926fa406..8998edd773f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinRuntimeTypeCastSurrounder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinRuntimeTypeCastSurrounder.kt @@ -52,7 +52,7 @@ public class KotlinRuntimeTypeCastSurrounder: KotlinExpressionSurrounder() { if (file !is JetCodeFragment) return false val context = file.analyzeFully() - val type = context[BindingContext.EXPRESSION_TYPE, expression] + val type = context.getType(expression) if (type == null) return false return TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type) diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinWhenSurrounder.java b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinWhenSurrounder.java index 790cb08418a..56fdcc421c6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinWhenSurrounder.java +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/surroundWith/expression/KotlinWhenSurrounder.java @@ -70,7 +70,7 @@ public class KotlinWhenSurrounder extends KotlinExpressionSurrounder { } private String getCodeTemplate(JetExpression expression) { - JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).get(BindingContext.EXPRESSION_TYPE, expression); + JetType type = ResolvePackage.analyze(expression, BodyResolveMode.PARTIAL).getType(expression); if (type != null) { ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.ENUM_CLASS) { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt index 73c9c54cee0..a1ae59e6e99 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToConcatenatedStringIntention.kt @@ -76,5 +76,5 @@ public class ConvertToConcatenatedStringIntention : JetSelfTargetingOffsetIndepe private fun String.quote(quote: String) = quote + this + quote - private fun JetExpression.isStringExpression() = KotlinBuiltIns.isString(BindingContextUtils.getRecordedTypeInfo(this, analyze())?.getType()) + private fun JetExpression.isStringExpression() = KotlinBuiltIns.isString(BindingContextUtils.getRecordedTypeInfo(this, analyze())?.type) } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt index b5dc1077e85..e72fba0a8a1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToExpressionBodyIntention.kt @@ -94,7 +94,7 @@ public class ConvertToExpressionBodyIntention : JetSelfTargetingOffsetIndependen val declaredType = (descriptor as? CallableDescriptor)?.getReturnType() ?: return false val scope = scopeExpression.analyze()[BindingContext.RESOLUTION_SCOPE, scopeExpression] ?: return false - val expressionType = expression.analyzeInContext(scope)[BindingContext.EXPRESSION_TYPE, expression] ?: return false + val expressionType = expression.analyzeInContext(scope).getType(expression) ?: return false return expressionType.isSubtypeOf(declaredType) } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToStringTemplateIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToStringTemplateIntention.kt index f8d950d9428..bb285cad837 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToStringTemplateIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertToStringTemplateIntention.kt @@ -39,7 +39,7 @@ public class ConvertToStringTemplateIntention : JetSelfTargetingOffsetIndependen override fun isApplicableTo(element: JetBinaryExpression): Boolean { if (element.getOperationToken() != JetTokens.PLUS) return false - val elementType = BindingContextUtils.getRecordedTypeInfo(element, element.analyze())?.getType() + val elementType = BindingContextUtils.getRecordedTypeInfo(element, element.analyze())?.type if (!KotlinBuiltIns.isString(elementType)) return false val left = element.getLeft() ?: return false @@ -80,7 +80,7 @@ public class ConvertToStringTemplateIntention : JetSelfTargetingOffsetIndependen val context = expression.analyze() val constant = ConstantExpressionEvaluator.evaluate(expression, DelegatingBindingTrace(context, "Trace for evaluating constant"), null) if (constant is IntegerValueTypeConstant) { - val elementType = BindingContextUtils.getRecordedTypeInfo(expression, context)?.getType()!! + val elementType = BindingContextUtils.getRecordedTypeInfo(expression, context)?.type!! constant.getValue(elementType).toString() } else { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt index f53593e9371..663e10244aa 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceWithInfixFunctionCallIntention.kt @@ -83,7 +83,7 @@ public open class ReplaceWithInfixFunctionCallIntention : JetSelfTargetingIntent val valueArguments = element.getValueArgumentList()?.getArguments() ?: listOf() val functionLiteralArguments = element.getFunctionLiteralArguments() val bindingContext = parent.analyze() - val receiverType = bindingContext[BindingContext.EXPRESSION_TYPE, receiver] + val receiverType = bindingContext.getType(receiver) if (receiverType == null) { if (bindingContext[BindingContext.QUALIFIER, receiver] != null) { intentionFailed(editor, "package.call") diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt index f6ce908c506..d16c1a74f16 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt @@ -47,7 +47,7 @@ fun specifyTypeExplicitly(declaration: JetNamedFunction, typeReference: JetTypeR fun expressionType(expression: JetExpression): JetType? { val bindingContext = expression.analyze() - return bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) + return bindingContext.getType(expression) } fun functionReturnType(function: JetNamedFunction): JetType? { diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/DeclarationUtils.java b/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/DeclarationUtils.java index b17197ad86a..4ef1dcbea34 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/DeclarationUtils.java +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/declarations/DeclarationUtils.java @@ -45,9 +45,7 @@ public class DeclarationUtils { private static JetType getPropertyTypeIfNeeded(@NotNull JetProperty property) { if (property.getTypeReference() != null) return null; - JetType type = ResolvePackage.analyze(property, BodyResolveMode.FULL).get( - BindingContext.EXPRESSION_TYPE, property.getInitializer() - ); + JetType type = ResolvePackage.analyze(property, BodyResolveMode.FULL).getType(property.getInitializer()); return type == null || type.isError() ? null : type; } diff --git a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java index 6b1fb0299ba..772a393b098 100644 --- a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java +++ b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java @@ -330,7 +330,7 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith private static boolean isArgumentTypeValid(BindingContext bindingContext, JetValueArgument argument, ValueParameterDescriptor param) { if (argument.getArgumentExpression() != null) { JetType paramType = getActualParameterType(param); - JetType exprType = bindingContext.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression()); + JetType exprType = bindingContext.getType(argument.getArgumentExpression()); return exprType == null || JetTypeChecker.DEFAULT.isSubtypeOf(exprType, paramType); } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java index 5f2abb2c794..6d6505b1a05 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddFunctionParametersFix.java @@ -138,7 +138,7 @@ public class AddFunctionParametersFix extends ChangeFunctionSignatureFix { if (i < parameters.size()) { validator.validateName(parameters.get(i).getName().asString()); - JetType argumentType = expression != null ? bindingContext.get(BindingContext.EXPRESSION_TYPE, expression) : null; + JetType argumentType = expression != null ? bindingContext.getType(expression) : null; JetType parameterType = parameters.get(i).getType(); if (argumentType != null && !JetTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameterType)) { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddNameToArgumentFix.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddNameToArgumentFix.java index e6d16e72ad4..146d0bde027 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddNameToArgumentFix.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddNameToArgumentFix.java @@ -74,7 +74,7 @@ public class AddNameToArgumentFix extends JetIntentionAction { if (resolvedCall == null) return Collections.emptyList(); CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor(); - JetType type = context.get(BindingContext.EXPRESSION_TYPE, argument.getArgumentExpression()); + JetType type = context.getType(argument.getArgumentExpression()); Set usedParameters = QuickFixUtil.getUsedParameters(callElement, null, callableDescriptor); List names = Lists.newArrayList(); for (ValueParameterDescriptor parameter: callableDescriptor.getValueParameters()) { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/CastExpressionFix.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/CastExpressionFix.java index 2379863057c..39b1e5a27c9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/CastExpressionFix.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/CastExpressionFix.java @@ -65,7 +65,7 @@ public class CastExpressionFix extends JetIntentionAction { public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { if (!super.isAvailable(project, editor, file)) return false; BindingContext context = ResolvePackage.analyzeFully((JetFile) file); - JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, element); + JetType expressionType = context.getType(element); return expressionType != null && JetTypeChecker.DEFAULT.isSubtypeOf(type, expressionType); } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionLiteralReturnTypeFix.java b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionLiteralReturnTypeFix.java index f9008afd38f..95aafeafe7f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionLiteralReturnTypeFix.java +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ChangeFunctionLiteralReturnTypeFix.java @@ -58,7 +58,7 @@ public class ChangeFunctionLiteralReturnTypeFix extends JetIntentionAction diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic); expectedType = diagnosticWithParameters.getB(); - expressionType = context.get(BindingContext.EXPRESSION_TYPE, expression); + expressionType = context.getType(expression); if (expressionType == null) { LOG.error("No type inferred: " + expression.getText()); return Collections.emptyList(); @@ -155,7 +155,7 @@ public class QuickFixFactoryForTypeMismatchError extends JetIntentionActionsFact JetParameter correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument); JetType valueArgumentType = diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE ? expressionType - : context.get(BindingContext.EXPRESSION_TYPE, valueArgument.getArgumentExpression()); + : context.getType(valueArgument.getArgumentExpression()); if (correspondingParameter != null && valueArgumentType != null) { JetCallableDeclaration callable = PsiTreeUtil.getParentOfType(correspondingParameter, JetCallableDeclaration.class, true); JetScope scope = callable != null ? JetScopeUtils.getResolutionScope(callable, context) : null; diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt index 1dca6cc8b55..9902466b66e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt @@ -55,7 +55,7 @@ private fun DeclarationDescriptor.render( private fun JetType.render(typeParameterNameMap: Map, fq: Boolean): String { val arguments = getArguments().map { it.getType().render(typeParameterNameMap, fq) } val typeString = getConstructor().getDeclarationDescriptor()!!.render(typeParameterNameMap, fq) - val typeArgumentString = if (arguments.notEmpty) arguments.joinToString(", ", "<", ">") else "" + val typeArgumentString = if (arguments.isNotEmpty()) arguments.joinToString(", ", "<", ">") else "" val nullifier = if (isMarkedNullable()) "?" else "" return "$typeString$typeArgumentString$nullifier" } @@ -73,10 +73,10 @@ private fun getTypeParameterNamesNotInScope(typeParameters: Collection { val typeParameters = LinkedHashSet() val arguments = getArguments() - if (arguments.empty) { + if (arguments.isEmpty()) { val descriptor = getConstructor().getDeclarationDescriptor() if (descriptor is TypeParameterDescriptor) { - typeParameters.add(descriptor as TypeParameterDescriptor) + typeParameters.add(descriptor) } } else { @@ -100,9 +100,9 @@ fun JetExpression.guessTypes( && getNonStrictParentOfType() == null) return array(builtIns.getUnitType()) // if we know the actual type of the expression - val theType1 = context[BindingContext.EXPRESSION_TYPE, this] + val theType1 = context.getType(this) if (theType1 != null) { - val dataFlowInfo = context[BindingContext.EXPRESSION_DATA_FLOW_INFO, this] + val dataFlowInfo = context[BindingContext.EXPRESSION_TYPE_INFO, this]?.dataFlowInfo val possibleTypes = dataFlowInfo?.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(this, theType1, context, module)) return if (possibleTypes != null && possibleTypes.isNotEmpty()) possibleTypes.copyToArray() else array(theType1) } @@ -117,12 +117,12 @@ fun JetExpression.guessTypes( return when { this is JetTypeConstraint -> { // expression itself is a type assertion - val constraint = (this as JetTypeConstraint) + val constraint = this array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!) } parent is JetTypeConstraint -> { // expression is on the left side of a type assertion - val constraint = (parent as JetTypeConstraint) + val constraint = parent array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!) } this is JetMultiDeclarationEntry -> { @@ -162,7 +162,7 @@ fun JetExpression.guessTypes( variable.guessType(context) } } - parent is JetPropertyDelegate && module != null -> { + parent is JetPropertyDelegate -> { val property = context[BindingContext.DECLARATION_TO_DESCRIPTOR, parent.getParent() as JetProperty] as PropertyDescriptor val delegateClassName = if (property.isVar()) "ReadWriteProperty" else "ReadOnlyProperty" val delegateClass = module.resolveTopLevelClass(FqName("kotlin.properties.$delegateClassName")) @@ -180,7 +180,7 @@ fun JetExpression.guessTypes( } private fun JetNamedDeclaration.guessType(context: BindingContext): Array { - val expectedTypes = SearchUtils.findAllReferences(this, getUseScope())!!.stream().map { ref -> + val expectedTypes = SearchUtils.findAllReferences(this, getUseScope())!!.sequence().map { ref -> if (ref is JetSimpleNameReference) { context[BindingContext.EXPECTED_EXPRESSION_TYPE, ref.expression] } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt index 01e320741f8..7b638af15c9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt @@ -140,7 +140,7 @@ object CreateCallableFromCallActionFactory : JetIntentionActionsFactory() { return when { !receiver.exists() -> TypeInfo.Empty receiver is Qualifier -> { - val qualifierType = context[BindingContext.EXPRESSION_TYPE, receiver.expression] + val qualifierType = context.getType(receiver.expression) if (qualifierType != null) return TypeInfo(qualifierType, Variance.IN_VARIANCE) val classifier = receiver.classifier as? JavaClassDescriptor ?: return null diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringUtil.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringUtil.java index 9e249935d94..573d523a8bb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringUtil.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/JetRefactoringUtil.java @@ -427,7 +427,7 @@ public class JetRefactoringUtil { if (addExpression) { JetExpression expression = (JetExpression)element; BindingContext bindingContext = ResolvePackage.analyze(expression, BodyResolveMode.FULL); - JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); + JetType expressionType = bindingContext.getType(expression); if (expressionType == null || !KotlinBuiltIns.isUnit(expressionType)) { expressions.add(expression); } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java index 1db422f1b9f..b5219542dd5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetChangeSignatureUsageProcessor.java @@ -322,7 +322,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro FunctionDescriptor functionDescriptor = context.get(BindingContext.FUNCTION, functionLiteral); assert functionDescriptor != null : "No descriptor for " + functionLiteral.getText(); - JetType samCallType = context.get(BindingContext.EXPRESSION_TYPE, callExpression); + JetType samCallType = context.getType(callExpression); if (samCallType == null) continue; result.add(new DeferredSAMUsage(functionLiteral, functionDescriptor, samCallType)); diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index f5315b3244f..b6bf73d1a3d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -85,8 +85,8 @@ import org.jetbrains.kotlin.utils.DFS.VisitedWithSet import java.util.* import kotlin.properties.Delegates -private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType()!! -private val DEFAULT_PARAMETER_TYPE = KotlinBuiltIns.getInstance().getNullableAnyType()!! +private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType() +private val DEFAULT_PARAMETER_TYPE = KotlinBuiltIns.getInstance().getNullableAnyType() private fun DeclarationDescriptor.renderForMessage(): String = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(this) @@ -158,7 +158,7 @@ private fun List.getResultTypeAndExpressions( if (expression == null) return null if (options.inferUnitTypeForUnusedValues && expression.isUsedAsStatement(bindingContext)) return null - return bindingContext[BindingContext.EXPRESSION_TYPE, expression] + return bindingContext.getType(expression) } val resultTypes = map(::instructionToType).filterNotNull() @@ -668,11 +668,11 @@ private fun ExtractionData.inferParametersInfo( originalDescriptor.getReturnType() ?: DEFAULT_RETURN_TYPE) } parameterExpression != null -> bindingContext[BindingContext.SMARTCAST, parameterExpression] - ?: bindingContext[BindingContext.EXPRESSION_TYPE, parameterExpression] + ?: bindingContext.getType(parameterExpression) ?: if (receiverToExtract.exists()) receiverToExtract.getType() else null receiverToExtract is ThisReceiver -> { val calleeExpression = resolvedCall!!.getCall().getCalleeExpression() - bindingContext[BindingContext.EXPRESSION_DATA_FLOW_INFO, calleeExpression]?.let { dataFlowInfo -> + bindingContext[BindingContext.EXPRESSION_TYPE_INFO, calleeExpression]?.dataFlowInfo?.let { dataFlowInfo -> val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract)) if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null } ?: receiverToExtract.getType() diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt index 59da9a932bf..38228049cf0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt @@ -147,7 +147,7 @@ public open class KotlinIntroduceParameterHandler: KotlinIntroduceHandlerBase() fun invoke(project: Project, editor: Editor, expression: JetExpression, targetParent: JetNamedDeclaration) { val context = expression.analyze() - val expressionType = context[BindingContext.EXPRESSION_TYPE, expression] + val expressionType = context.getType(expression) if (expressionType.isUnit() || expressionType.isNothing()) { val message = JetRefactoringBundle.message( "cannot.introduce.parameter.of.0.type", diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java index f4ca2f71be1..0b705dbff0e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceVariable/KotlinIntroduceVariableHandler.java @@ -127,7 +127,7 @@ public class KotlinIntroduceVariableHandler extends KotlinIntroduceHandlerBase { AnalysisResult analysisResult = ResolvePackage.analyzeAndGetResult(expression); final BindingContext bindingContext = analysisResult.getBindingContext(); - final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); //can be null or error type + final JetType expressionType = bindingContext.getType(expression); //can be null or error type JetScope scope = bindingContext.get(BindingContext.RESOLUTION_SCOPE, expression); if (scope != null) { DataFlowInfo dataFlowInfo = BindingContextUtilPackage.getDataFlowInfo(bindingContext, expression); diff --git a/idea/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/JetPsiUnifier.kt b/idea/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/JetPsiUnifier.kt index aa88370f539..92278dedfa9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/JetPsiUnifier.kt +++ b/idea/src/org/jetbrains/kotlin/idea/util/psi/patternMatching/JetPsiUnifier.kt @@ -728,7 +728,7 @@ public class JetPsiUnifier( } private fun PsiElement.checkType(parameter: UnifierParameter): Boolean { - val targetElementType = (this as? JetExpression)?.let { it.bindingContext[BindingContext.EXPRESSION_TYPE, it] } + val targetElementType = (this as? JetExpression)?.let { it.bindingContext.getType(it) } return targetElementType != null && JetTypeChecker.DEFAULT.isSubtypeOf(targetElementType, parameter.expectedType) } diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractPartialBodyResolveTest.kt b/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractPartialBodyResolveTest.kt index 878dd91d33b..b4fc6d7193a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractPartialBodyResolveTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/AbstractPartialBodyResolveTest.kt @@ -157,7 +157,7 @@ public abstract class AbstractPartialBodyResolveTest : JetLightCodeInsightFixtur else { expression } - val type = bindingContext[BindingContext.EXPRESSION_TYPE, expressionWithType] + val type = bindingContext.getType(expressionWithType) return ResolveData(target, type, processedStatements) } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index b48dd5fd33a..591e1a87aca 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -350,7 +350,7 @@ public final class ExpressionVisitor extends TranslatorVisitor { assert right != null; JetType rightType = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.TYPE, right); - JetType leftType = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.EXPRESSION_TYPE, expression.getLeft()); + JetType leftType = BindingContextUtils.getNotNullType(context.bindingContext(), expression.getLeft()); if (TypeUtils.isNullableType(rightType) || !TypeUtils.isNullableType(leftType)) { return jsExpression.source(expression); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java index 93bd7e374e0..a36230498a1 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/StringTemplateTranslator.java @@ -89,7 +89,7 @@ public final class StringTemplateTranslator extends AbstractTranslator { return; } - JetType type = context().bindingContext().get(BindingContext.EXPRESSION_TYPE, entryExpression); + JetType type = context().bindingContext().getType(entryExpression); if (type == null || type.isMarkedNullable()) { append(TopLevelFIF.TO_STRING.apply((JsExpression) null, Collections.singletonList(translatedExpression), context())); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/UnaryOperationTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/UnaryOperationTranslator.java index 772768743f0..84df664fe62 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/UnaryOperationTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/operation/UnaryOperationTranslator.java @@ -55,7 +55,7 @@ public final class UnaryOperationTranslator { IElementType operationToken = expression.getOperationReference().getReferencedNameElementType(); if (operationToken == JetTokens.EXCLEXCL) { JetExpression baseExpression = getBaseExpression(expression); - JetType type = BindingContextUtils.getNotNull(context.bindingContext(), BindingContext.EXPRESSION_TYPE, baseExpression); + JetType type = BindingContextUtils.getNotNullType(context.bindingContext(), baseExpression); JsExpression translatedExpression = translateAsExpression(baseExpression, context); return type.isMarkedNullable() ? sure(translatedExpression, context) : translatedExpression; } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java index 48b6f9eded3..79fac375103 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java @@ -160,7 +160,7 @@ public final class BindingUtils { public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression, @NotNull CompileTimeConstant constant) { if (constant != null) { if (constant instanceof IntegerValueTypeConstant) { - JetType expectedType = context.get(BindingContext.EXPRESSION_TYPE, expression); + JetType expectedType = context.getType(expression); return ((IntegerValueTypeConstant) constant).getValue(expectedType == null ? TypeUtils.NO_EXPECTED_TYPE : expectedType); } return constant.getValue(); @@ -210,7 +210,7 @@ public final class BindingUtils { @NotNull public static JetType getTypeForExpression(@NotNull BindingContext context, @NotNull JetExpression expression) { - return BindingContextUtils.getNotNull(context, BindingContext.EXPRESSION_TYPE, expression); + return BindingContextUtils.getNotNullType(context, expression); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java index 4197d2f3b5e..03cafc45b07 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java @@ -162,7 +162,7 @@ public final class JsDescriptorUtils { @Nullable public static Name getNameIfStandardType(@NotNull JetExpression expression, @NotNull TranslationContext context) { - JetType type = context.bindingContext().get(BindingContext.EXPRESSION_TYPE, expression); + JetType type = context.bindingContext().getType(expression); return type != null ? DescriptorUtilsPackage.getNameIfStandardType(type) : null; }