Add feature support for "smart casts on variables in closures"
So #KT-14486 Fixed
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
+2
-1
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -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? {
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user