Add feature support for "smart casts on variables in closures"

So #KT-14486 Fixed
This commit is contained in:
Mikhail Glukhikh
2017-08-10 18:28:28 +03:00
parent a086863561
commit a12877e51c
9 changed files with 29 additions and 15 deletions
@@ -608,7 +608,7 @@ public class BodyResolver {
KtExpression body = anonymousInitializer.getBody(); KtExpression body = anonymousInitializer.getBody();
if (body != null) { if (body != null) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration( PreliminaryDeclarationVisitor.Companion.createForDeclaration(
(KtDeclaration) anonymousInitializer.getParent().getParent(), trace); (KtDeclaration) anonymousInitializer.getParent().getParent(), trace, languageVersionSettings);
expressionTypingServices.getTypeInfo( expressionTypingServices.getTypeInfo(
scopeForInitializers, body, NO_EXPECTED_TYPE, outerDataFlowInfo, trace, /*isStatement = */true scopeForInitializers, body, NO_EXPECTED_TYPE, outerDataFlowInfo, trace, /*isStatement = */true
); );
@@ -680,7 +680,7 @@ public class BodyResolver {
) { ) {
computeDeferredType(propertyDescriptor.getReturnType()); computeDeferredType(propertyDescriptor.getReturnType());
PreliminaryDeclarationVisitor.Companion.createForDeclaration(property, trace); PreliminaryDeclarationVisitor.Companion.createForDeclaration(property, trace, languageVersionSettings);
KtExpression initializer = property.getInitializer(); KtExpression initializer = property.getInitializer();
LexicalScope propertyHeaderScope = ScopeUtils.makeScopeForPropertyHeader(getScopeForProperty(c, property), propertyDescriptor); LexicalScope propertyHeaderScope = ScopeUtils.makeScopeForPropertyHeader(getScopeForProperty(c, property), propertyDescriptor);
@@ -851,7 +851,7 @@ public class BodyResolver {
// Creates wrapper scope for header resolution if necessary (see resolveSecondaryConstructorBody) // Creates wrapper scope for header resolution if necessary (see resolveSecondaryConstructorBody)
@Nullable Function1<LexicalScope, LexicalScope> headerScopeFactory @Nullable Function1<LexicalScope, LexicalScope> headerScopeFactory
) { ) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace); PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace, overloadChecker); LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace, overloadChecker);
List<KtParameter> valueParameters = function.getValueParameters(); List<KtParameter> valueParameters = function.getValueParameters();
List<ValueParameterDescriptor> valueParameterDescriptors = functionDescriptor.getValueParameters(); List<ValueParameterDescriptor> valueParameterDescriptors = functionDescriptor.getValueParameters();
@@ -1154,7 +1154,7 @@ public class DescriptorResolver {
@NotNull FunctionDescriptor functionDescriptor @NotNull FunctionDescriptor functionDescriptor
) { ) {
return wrappedTypeFactory.createRecursionIntolerantDeferredType(trace, () -> { return wrappedTypeFactory.createRecursionIntolerantDeferredType(trace, () -> {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace); PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
KotlinType type = expressionTypingServices.getBodyExpressionType( KotlinType type = expressionTypingServices.getBodyExpressionType(
trace, scope, dataFlowInfo, function, functionDescriptor); trace, scope, dataFlowInfo, function, functionDescriptor);
KotlinType result = transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace); KotlinType result = transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace);
@@ -84,7 +84,8 @@ class VariableTypeAndInitializerResolver(
wrappedTypeFactory.createRecursionIntolerantDeferredType( wrappedTypeFactory.createRecursionIntolerantDeferredType(
trace trace
) { ) {
PreliminaryDeclarationVisitor.createForDeclaration(variable, trace) PreliminaryDeclarationVisitor.createForDeclaration(variable, trace,
expressionTypingServices.languageVersionSettings)
val initializerType = resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local) val initializerType = resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace) transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace)
} }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.smartcasts
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableNothing import org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableNothing
import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
@@ -378,7 +379,8 @@ object DataFlowValueFactory {
val variableContainingDeclaration = variableDescriptor.containingDeclaration val variableContainingDeclaration = variableDescriptor.containingDeclaration
if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) { if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) {
// stable iff we have no writers in closures AND this closure is AFTER all writers // stable iff we have no writers in closures AND this closure is AFTER all writers
return if (hasNoWritersInClosures(variableContainingDeclaration, writers, bindingContext) && return if (preliminaryVisitor.languageVersionSettings.supportsFeature(LanguageFeature.CapturedInClosureSmartCasts) &&
hasNoWritersInClosures(variableContainingDeclaration, writers, bindingContext) &&
isAccessedInsideClosureAfterAllWriters(writers, accessElement)) { isAccessedInsideClosureAfterAllWriters(writers, accessElement)) {
STABLE_VARIABLE STABLE_VARIABLE
} }
@@ -17,10 +17,10 @@
package org.jetbrains.kotlin.types.expressions; package org.jetbrains.kotlin.types.expressions;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ScriptDescriptor; import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
@@ -68,6 +68,11 @@ public class ExpressionTypingServices {
this.expressionTypingFacade = facade; this.expressionTypingFacade = facade;
} }
@NotNull
public LanguageVersionSettings getLanguageVersionSettings() {
return expressionTypingComponents.languageVersionSettings;
}
@NotNull public StatementFilter getStatementFilter() { @NotNull public StatementFilter getStatementFilter() {
return statementFilter; return statementFilter;
} }
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.types.expressions package org.jetbrains.kotlin.types.expressions
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -26,7 +27,10 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
class PreliminaryDeclarationVisitor(val declaration: KtDeclaration): AssignedVariablesSearcher() { class PreliminaryDeclarationVisitor(
val declaration: KtDeclaration,
val languageVersionSettings: LanguageVersionSettings
): AssignedVariablesSearcher() {
override fun writers(variableDescriptor: VariableDescriptor): MutableSet<Writer> { override fun writers(variableDescriptor: VariableDescriptor): MutableSet<Writer> {
lazyTrigger lazyTrigger
@@ -39,17 +43,18 @@ class PreliminaryDeclarationVisitor(val declaration: KtDeclaration): AssignedVar
companion object { companion object {
fun createForExpression(expression: KtExpression, trace: BindingTrace) { fun createForExpression(expression: KtExpression, trace: BindingTrace, languageVersionSettings: LanguageVersionSettings) {
expression.getStrictParentOfType<KtDeclaration>()?.let { createForDeclaration(it, trace) } expression.getStrictParentOfType<KtDeclaration>()?.let { createForDeclaration(it, trace, languageVersionSettings) }
} }
private fun topMostNonClassDeclaration(declaration: KtDeclaration) = private fun topMostNonClassDeclaration(declaration: KtDeclaration) =
declaration.parentsWithSelf.filterIsInstance<KtDeclaration>().findLast { it !is KtClassOrObject } ?: declaration declaration.parentsWithSelf.filterIsInstance<KtDeclaration>().findLast { it !is KtClassOrObject } ?: declaration
fun createForDeclaration(declaration: KtDeclaration, trace: BindingTrace) { fun createForDeclaration(declaration: KtDeclaration, trace: BindingTrace, languageVersionSettings: LanguageVersionSettings) {
val visitorOwner = topMostNonClassDeclaration(declaration) val visitorOwner = topMostNonClassDeclaration(declaration)
if (trace.get(BindingContext.PRELIMINARY_VISITOR, visitorOwner) != null) return if (trace.get(BindingContext.PRELIMINARY_VISITOR, visitorOwner) != null) return
trace.record(BindingContext.PRELIMINARY_VISITOR, visitorOwner, PreliminaryDeclarationVisitor(visitorOwner)) trace.record(BindingContext.PRELIMINARY_VISITOR, visitorOwner,
PreliminaryDeclarationVisitor(visitorOwner, languageVersionSettings))
} }
fun getVisitorByVariable(variableDescriptor: VariableDescriptor, bindingContext: BindingContext): PreliminaryDeclarationVisitor? { fun getVisitorByVariable(variableDescriptor: VariableDescriptor, bindingContext: BindingContext): PreliminaryDeclarationVisitor? {
@@ -9,7 +9,7 @@ fun foo(s: String?) {
} }
if (x != null) { if (x != null) {
run { run {
<!DEBUG_INFO_SMARTCAST!>x<!>.hashCode() <!SMARTCAST_IMPOSSIBLE!>x<!>.hashCode()
} }
} }
} }
@@ -46,7 +46,7 @@ import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
contextDependency: ContextDependency = ContextDependency.INDEPENDENT, contextDependency: ContextDependency = ContextDependency.INDEPENDENT,
expressionTypingServices: ExpressionTypingServices = contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>() expressionTypingServices: ExpressionTypingServices = contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
): KotlinTypeInfo { ): KotlinTypeInfo {
PreliminaryDeclarationVisitor.createForExpression(this, trace) PreliminaryDeclarationVisitor.createForExpression(this, trace, expressionTypingServices.languageVersionSettings)
return expressionTypingServices.getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement, contextExpression, contextDependency) return expressionTypingServices.getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement, contextExpression, contextDependency)
} }
@@ -54,7 +54,8 @@ class CodeFragmentAnalyzer(
when (codeFragmentElement) { when (codeFragmentElement) {
is KtExpression -> { is KtExpression -> {
PreliminaryDeclarationVisitor.createForExpression(codeFragmentElement, trace) PreliminaryDeclarationVisitor.createForExpression(codeFragmentElement, trace,
expressionTypingServices.languageVersionSettings)
expressionTypingServices.getTypeInfo( expressionTypingServices.getTypeInfo(
scopeForContextElement, scopeForContextElement,
codeFragmentElement, codeFragmentElement,