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();
if (body != null) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(
(KtDeclaration) anonymousInitializer.getParent().getParent(), trace);
(KtDeclaration) anonymousInitializer.getParent().getParent(), trace, languageVersionSettings);
expressionTypingServices.getTypeInfo(
scopeForInitializers, body, NO_EXPECTED_TYPE, outerDataFlowInfo, trace, /*isStatement = */true
);
@@ -680,7 +680,7 @@ public class BodyResolver {
) {
computeDeferredType(propertyDescriptor.getReturnType());
PreliminaryDeclarationVisitor.Companion.createForDeclaration(property, trace);
PreliminaryDeclarationVisitor.Companion.createForDeclaration(property, trace, languageVersionSettings);
KtExpression initializer = property.getInitializer();
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)
@Nullable Function1<LexicalScope, LexicalScope> headerScopeFactory
) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace);
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace, overloadChecker);
List<KtParameter> valueParameters = function.getValueParameters();
List<ValueParameterDescriptor> valueParameterDescriptors = functionDescriptor.getValueParameters();
@@ -1154,7 +1154,7 @@ public class DescriptorResolver {
@NotNull FunctionDescriptor functionDescriptor
) {
return wrappedTypeFactory.createRecursionIntolerantDeferredType(trace, () -> {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace);
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
KotlinType type = expressionTypingServices.getBodyExpressionType(
trace, scope, dataFlowInfo, function, functionDescriptor);
KotlinType result = transformAnonymousTypeIfNeeded(functionDescriptor, function, type, trace);
@@ -84,7 +84,8 @@ class VariableTypeAndInitializerResolver(
wrappedTypeFactory.createRecursionIntolerantDeferredType(
trace
) {
PreliminaryDeclarationVisitor.createForDeclaration(variable, trace)
PreliminaryDeclarationVisitor.createForDeclaration(variable, trace,
expressionTypingServices.languageVersionSettings)
val initializerType = resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace, local)
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.builtins.KotlinBuiltIns.isNullableNothing
import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
@@ -378,7 +379,8 @@ object DataFlowValueFactory {
val variableContainingDeclaration = variableDescriptor.containingDeclaration
if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) {
// 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)) {
STABLE_VARIABLE
}
@@ -17,10 +17,10 @@
package org.jetbrains.kotlin.types.expressions;
import com.intellij.psi.tree.IElementType;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ScriptDescriptor;
@@ -68,6 +68,11 @@ public class ExpressionTypingServices {
this.expressionTypingFacade = facade;
}
@NotNull
public LanguageVersionSettings getLanguageVersionSettings() {
return expressionTypingComponents.languageVersionSettings;
}
@NotNull public StatementFilter getStatementFilter() {
return statementFilter;
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.types.expressions
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.psi.KtClassOrObject
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.DescriptorToSourceUtils
class PreliminaryDeclarationVisitor(val declaration: KtDeclaration): AssignedVariablesSearcher() {
class PreliminaryDeclarationVisitor(
val declaration: KtDeclaration,
val languageVersionSettings: LanguageVersionSettings
): AssignedVariablesSearcher() {
override fun writers(variableDescriptor: VariableDescriptor): MutableSet<Writer> {
lazyTrigger
@@ -39,17 +43,18 @@ class PreliminaryDeclarationVisitor(val declaration: KtDeclaration): AssignedVar
companion object {
fun createForExpression(expression: KtExpression, trace: BindingTrace) {
expression.getStrictParentOfType<KtDeclaration>()?.let { createForDeclaration(it, trace) }
fun createForExpression(expression: KtExpression, trace: BindingTrace, languageVersionSettings: LanguageVersionSettings) {
expression.getStrictParentOfType<KtDeclaration>()?.let { createForDeclaration(it, trace, languageVersionSettings) }
}
private fun topMostNonClassDeclaration(declaration: KtDeclaration) =
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)
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? {
@@ -9,7 +9,7 @@ fun foo(s: String?) {
}
if (x != null) {
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,
expressionTypingServices: ExpressionTypingServices = contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
): KotlinTypeInfo {
PreliminaryDeclarationVisitor.createForExpression(this, trace)
PreliminaryDeclarationVisitor.createForExpression(this, trace, expressionTypingServices.languageVersionSettings)
return expressionTypingServices.getTypeInfo(scope, this, expectedType, dataFlowInfo, trace, isStatement, contextExpression, contextDependency)
}
@@ -54,7 +54,8 @@ class CodeFragmentAnalyzer(
when (codeFragmentElement) {
is KtExpression -> {
PreliminaryDeclarationVisitor.createForExpression(codeFragmentElement, trace)
PreliminaryDeclarationVisitor.createForExpression(codeFragmentElement, trace,
expressionTypingServices.languageVersionSettings)
expressionTypingServices.getTypeInfo(
scopeForContextElement,
codeFragmentElement,