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; }