Refactor: extract type checking code for local variables to a separate component, extract code that creates descriptors for local variable out of DescriptorResolver
This commit is contained in:
@@ -20,8 +20,8 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.Pair;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.collections.SetsKt;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
@@ -42,22 +42,17 @@ import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.DataClassUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils;
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
|
||||
import org.jetbrains.kotlin.storage.StorageManager;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -75,31 +70,25 @@ public class DescriptorResolver {
|
||||
|
||||
@NotNull private final TypeResolver typeResolver;
|
||||
@NotNull private final AnnotationResolver annotationResolver;
|
||||
@NotNull private final ExpressionTypingServices expressionTypingServices;
|
||||
@NotNull private final DelegatedPropertyResolver delegatedPropertyResolver;
|
||||
@NotNull private final StorageManager storageManager;
|
||||
@NotNull private final KotlinBuiltIns builtIns;
|
||||
@NotNull private final ConstantExpressionEvaluator constantExpressionEvaluator;
|
||||
@NotNull private final SupertypeLoopChecker supertypeLoopsResolver;
|
||||
@NotNull private final VariableTypeResolver variableTypeResolver;
|
||||
|
||||
public DescriptorResolver(
|
||||
@NotNull AnnotationResolver annotationResolver,
|
||||
@NotNull KotlinBuiltIns builtIns,
|
||||
@NotNull DelegatedPropertyResolver delegatedPropertyResolver,
|
||||
@NotNull ExpressionTypingServices expressionTypingServices,
|
||||
@NotNull StorageManager storageManager,
|
||||
@NotNull TypeResolver typeResolver,
|
||||
@NotNull ConstantExpressionEvaluator constantExpressionEvaluator,
|
||||
@NotNull SupertypeLoopChecker supertypeLoopsResolver
|
||||
@NotNull SupertypeLoopChecker supertypeLoopsResolver,
|
||||
@NotNull VariableTypeResolver variableTypeResolver
|
||||
) {
|
||||
this.annotationResolver = annotationResolver;
|
||||
this.builtIns = builtIns;
|
||||
this.delegatedPropertyResolver = delegatedPropertyResolver;
|
||||
this.expressionTypingServices = expressionTypingServices;
|
||||
this.storageManager = storageManager;
|
||||
this.typeResolver = typeResolver;
|
||||
this.constantExpressionEvaluator = constantExpressionEvaluator;
|
||||
this.supertypeLoopsResolver = supertypeLoopsResolver;
|
||||
this.variableTypeResolver = variableTypeResolver;
|
||||
}
|
||||
|
||||
public List<KotlinType> resolveSupertypes(
|
||||
@@ -670,84 +659,6 @@ public class DescriptorResolver {
|
||||
return variableDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VariableDescriptor resolveLocalVariableDescriptor(
|
||||
LexicalScope scope,
|
||||
KtVariableDeclaration variable,
|
||||
DataFlowInfo dataFlowInfo,
|
||||
BindingTrace trace
|
||||
) {
|
||||
DeclarationDescriptor containingDeclaration = scope.getOwnerDescriptor();
|
||||
VariableDescriptor result;
|
||||
KotlinType type;
|
||||
if (KtPsiUtil.isScriptDeclaration(variable)) {
|
||||
PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(
|
||||
containingDeclaration,
|
||||
annotationResolver.resolveAnnotationsWithArguments(scope, variable.getModifierList(), trace),
|
||||
Modality.FINAL,
|
||||
Visibilities.INTERNAL,
|
||||
variable.isVar(),
|
||||
KtPsiUtil.safeName(variable.getName()),
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
KotlinSourceElementKt.toSourceElement(variable),
|
||||
/* lateInit = */ false,
|
||||
/* isConst = */ false
|
||||
);
|
||||
// For a local variable the type must not be deferred
|
||||
type = getVariableType(propertyDescriptor, scope, variable, dataFlowInfo, false, trace);
|
||||
|
||||
ReceiverParameterDescriptor receiverParameter = ((ScriptDescriptor) containingDeclaration).getThisAsReceiverParameter();
|
||||
propertyDescriptor.setType(type, Collections.<TypeParameterDescriptor>emptyList(), receiverParameter, (KotlinType) null);
|
||||
initializeWithDefaultGetterSetter(propertyDescriptor);
|
||||
trace.record(BindingContext.VARIABLE, variable, propertyDescriptor);
|
||||
result = propertyDescriptor;
|
||||
}
|
||||
else {
|
||||
LocalVariableDescriptor variableDescriptor =
|
||||
resolveLocalVariableDescriptorWithType(scope, variable, null, trace);
|
||||
// For a local variable the type must not be deferred
|
||||
type = getVariableType(variableDescriptor, scope, variable, dataFlowInfo, false, trace);
|
||||
variableDescriptor.setOutType(type);
|
||||
result = variableDescriptor;
|
||||
}
|
||||
// Type annotations also should be resolved
|
||||
ForceResolveUtil.forceResolveAllContents(type.getAnnotations());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void initializeWithDefaultGetterSetter(PropertyDescriptorImpl propertyDescriptor) {
|
||||
PropertyGetterDescriptorImpl getter = propertyDescriptor.getGetter();
|
||||
if (getter == null && !Visibilities.isPrivate(propertyDescriptor.getVisibility())) {
|
||||
getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.Companion.getEMPTY());
|
||||
getter.initialize(propertyDescriptor.getType());
|
||||
}
|
||||
|
||||
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
|
||||
if (setter == null && propertyDescriptor.isVar()) {
|
||||
setter = DescriptorFactory.createDefaultSetter(propertyDescriptor, Annotations.Companion.getEMPTY());
|
||||
}
|
||||
propertyDescriptor.initialize(getter, setter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LocalVariableDescriptor resolveLocalVariableDescriptorWithType(
|
||||
@NotNull LexicalScope scope,
|
||||
@NotNull KtVariableDeclaration variable,
|
||||
@Nullable KotlinType type,
|
||||
@NotNull BindingTrace trace
|
||||
) {
|
||||
LocalVariableDescriptor variableDescriptor = new LocalVariableDescriptor(
|
||||
scope.getOwnerDescriptor(),
|
||||
annotationResolver.resolveAnnotationsWithArguments(scope, variable.getModifierList(), trace),
|
||||
KtPsiUtil.safeName(variable.getName()),
|
||||
type,
|
||||
variable.isVar(),
|
||||
KotlinSourceElementKt.toSourceElement(variable)
|
||||
);
|
||||
trace.record(BindingContext.VARIABLE, variable, variableDescriptor);
|
||||
return variableDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PropertyDescriptor resolvePropertyDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@@ -824,9 +735,10 @@ public class DescriptorResolver {
|
||||
ReceiverParameterDescriptor receiverDescriptor =
|
||||
DescriptorFactory.createExtensionReceiverParameterForCallable(propertyDescriptor, receiverType);
|
||||
|
||||
KotlinType type = getVariableType(propertyDescriptor,
|
||||
ScopeUtils.makeScopeForPropertyInitializer(scopeWithTypeParameters, propertyDescriptor),
|
||||
property, dataFlowInfo, true, trace);
|
||||
KotlinType type = variableTypeResolver.process(
|
||||
propertyDescriptor, ScopeUtils.makeScopeForPropertyInitializer(scopeWithTypeParameters, propertyDescriptor),
|
||||
property, dataFlowInfo, true, trace
|
||||
);
|
||||
|
||||
propertyDescriptor.setType(type, typeParameterDescriptors, getDispatchReceiverParameterIfNeeded(containingDeclaration),
|
||||
receiverDescriptor);
|
||||
@@ -858,127 +770,6 @@ public class DescriptorResolver {
|
||||
return hasBody;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinType getVariableType(
|
||||
@NotNull final VariableDescriptorWithInitializerImpl variableDescriptor,
|
||||
@NotNull final LexicalScope scopeForInitializer,
|
||||
@NotNull final KtVariableDeclaration variable,
|
||||
@NotNull final DataFlowInfo dataFlowInfo,
|
||||
boolean notLocal,
|
||||
@NotNull final BindingTrace trace
|
||||
) {
|
||||
KtTypeReference propertyTypeRef = variable.getTypeReference();
|
||||
|
||||
boolean hasDelegate = variable instanceof KtProperty && ((KtProperty) variable).hasDelegateExpression();
|
||||
if (propertyTypeRef == null) {
|
||||
if (!variable.hasInitializer()) {
|
||||
if (hasDelegate && variableDescriptor instanceof PropertyDescriptor) {
|
||||
final KtProperty property = (KtProperty) variable;
|
||||
if (property.hasDelegateExpression()) {
|
||||
return DeferredType.createRecursionIntolerant(
|
||||
storageManager,
|
||||
trace,
|
||||
new Function0<KotlinType>() {
|
||||
@Override
|
||||
public KotlinType invoke() {
|
||||
return resolveDelegatedPropertyType(property, (PropertyDescriptor) variableDescriptor, scopeForInitializer,
|
||||
property.getDelegateExpression(), dataFlowInfo, trace);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!notLocal) {
|
||||
trace.report(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.on(variable));
|
||||
}
|
||||
return ErrorUtils.createErrorType("No type, no body");
|
||||
}
|
||||
else {
|
||||
if (notLocal) {
|
||||
return DeferredType.createRecursionIntolerant(
|
||||
storageManager,
|
||||
trace,
|
||||
new Function0<KotlinType>() {
|
||||
@Override
|
||||
public KotlinType invoke() {
|
||||
PreliminaryDeclarationVisitor.Companion.createForDeclaration(variable, trace);
|
||||
KotlinType
|
||||
initializerType = resolveInitializerType(scopeForInitializer, variable.getInitializer(), dataFlowInfo, trace);
|
||||
setConstantForVariableIfNeeded(variableDescriptor, scopeForInitializer, variable, dataFlowInfo, initializerType, trace);
|
||||
return transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
KotlinType initializerType = resolveInitializerType(scopeForInitializer, variable.getInitializer(), dataFlowInfo, trace);
|
||||
setConstantForVariableIfNeeded(variableDescriptor, scopeForInitializer, variable, dataFlowInfo, initializerType, trace);
|
||||
return initializerType;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
KotlinType type = typeResolver.resolveType(scopeForInitializer, propertyTypeRef, trace, true);
|
||||
setConstantForVariableIfNeeded(variableDescriptor, scopeForInitializer, variable, dataFlowInfo, type, trace);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
private void setConstantForVariableIfNeeded(
|
||||
@NotNull final VariableDescriptorWithInitializerImpl variableDescriptor,
|
||||
@NotNull final LexicalScope scope,
|
||||
@NotNull final KtVariableDeclaration variable,
|
||||
@NotNull final DataFlowInfo dataFlowInfo,
|
||||
@NotNull final KotlinType variableType,
|
||||
@NotNull final BindingTrace trace
|
||||
) {
|
||||
if (!shouldRecordInitializerForProperty(variableDescriptor, variableType)) return;
|
||||
|
||||
if (!variable.hasInitializer()) return;
|
||||
|
||||
variableDescriptor.setCompileTimeInitializer(
|
||||
storageManager.createRecursionTolerantNullableLazyValue(new Function0<ConstantValue<?>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public ConstantValue<?> invoke() {
|
||||
KtExpression initializer = variable.getInitializer();
|
||||
KotlinType initializerType = expressionTypingServices.safeGetType(scope, initializer, variableType, dataFlowInfo, trace);
|
||||
CompileTimeConstant<?> constant = constantExpressionEvaluator.evaluateExpression(initializer, trace, initializerType);
|
||||
|
||||
if (constant == null) return null;
|
||||
|
||||
if (constant.getUsesNonConstValAsConstant() && variableDescriptor.isConst()) {
|
||||
trace.report(Errors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION.on(initializer));
|
||||
}
|
||||
|
||||
return constant.toConstantValue(initializerType);
|
||||
}
|
||||
}, null)
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinType resolveDelegatedPropertyType(
|
||||
@NotNull KtProperty property,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull LexicalScope scopeForInitializer,
|
||||
@NotNull KtExpression delegateExpression,
|
||||
@NotNull DataFlowInfo dataFlowInfo,
|
||||
@NotNull BindingTrace trace
|
||||
) {
|
||||
|
||||
KotlinType type = delegatedPropertyResolver.resolveDelegateExpression(
|
||||
delegateExpression, property, propertyDescriptor, scopeForInitializer, trace, dataFlowInfo);
|
||||
|
||||
if (type != null) {
|
||||
LexicalScope delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForInitializer, propertyDescriptor);
|
||||
KotlinType getterReturnType = delegatedPropertyResolver
|
||||
.getDelegatedPropertyGetMethodReturnType(propertyDescriptor, delegateExpression, type, trace, delegateFunctionsScope);
|
||||
if (getterReturnType != null) {
|
||||
return getterReturnType;
|
||||
}
|
||||
}
|
||||
return ErrorUtils.createErrorType("Type from delegate");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
/*package*/ static KotlinType transformAnonymousTypeIfNeeded(
|
||||
@@ -1005,15 +796,6 @@ public class DescriptorResolver {
|
||||
return type;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private KotlinType resolveInitializerType(
|
||||
@NotNull LexicalScope scope,
|
||||
@NotNull KtExpression initializer,
|
||||
@NotNull DataFlowInfo dataFlowInfo,
|
||||
@NotNull BindingTrace trace
|
||||
) {
|
||||
return expressionTypingServices.safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo, trace);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PropertySetterDescriptor resolvePropertySetterDescriptor(
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||
import org.jetbrains.kotlin.psi.KtVariableDeclaration
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope
|
||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.*
|
||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||
|
||||
class LocalVariableResolver(
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val modifiersChecker: ModifiersChecker,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val annotationResolver: AnnotationResolver,
|
||||
private val variableTypeResolver: VariableTypeResolver
|
||||
) {
|
||||
|
||||
fun process(
|
||||
property: KtProperty,
|
||||
typingContext: ExpressionTypingContext,
|
||||
scope: LexicalWritableScope,
|
||||
facade: ExpressionTypingFacade
|
||||
): KotlinTypeInfo {
|
||||
val context = typingContext.replaceContextDependency(ContextDependency.INDEPENDENT).replaceScope(scope)
|
||||
val receiverTypeRef = property.receiverTypeReference
|
||||
if (receiverTypeRef != null) {
|
||||
context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef))
|
||||
}
|
||||
|
||||
val getter = property.getter
|
||||
if (getter != null) {
|
||||
context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter))
|
||||
}
|
||||
|
||||
val setter = property.setter
|
||||
if (setter != null) {
|
||||
context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter))
|
||||
}
|
||||
|
||||
val delegateExpression = property.delegateExpression
|
||||
if (delegateExpression != null) {
|
||||
expressionTypingServices.getTypeInfo(delegateExpression, context)
|
||||
context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.delegate!!))
|
||||
}
|
||||
|
||||
val propertyDescriptor = resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace)
|
||||
val initializer = property.initializer
|
||||
var typeInfo: KotlinTypeInfo
|
||||
if (initializer != null) {
|
||||
val outType = propertyDescriptor.getType()
|
||||
typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType))
|
||||
val dataFlowInfo = typeInfo.dataFlowInfo
|
||||
val type = typeInfo.type
|
||||
// At this moment we do not take initializer value into account if type is given for a property
|
||||
// We can comment first part of this condition to take them into account, like here: var s: String? = "xyz"
|
||||
// In this case s will be not-nullable until it is changed
|
||||
if (property.typeReference == null && type != null) {
|
||||
val variableDataFlowValue = DataFlowValueFactory.createDataFlowValueForProperty(
|
||||
property, propertyDescriptor, context.trace.bindingContext,
|
||||
DescriptorUtils.getContainingModuleOrNull(scope.ownerDescriptor))
|
||||
val initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context)
|
||||
// We cannot say here anything new about initializerDataFlowValue
|
||||
// except it has the same value as variableDataFlowValue
|
||||
typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.assign(variableDataFlowValue, initializerDataFlowValue))
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeInfo = noTypeInfo(context)
|
||||
}
|
||||
|
||||
ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, propertyDescriptor)
|
||||
|
||||
scope.addVariableDescriptor(propertyDescriptor)
|
||||
property.checkTypeReferences(context.trace)
|
||||
modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor)
|
||||
identifierChecker.checkDeclaration(property, context.trace)
|
||||
return typeInfo.replaceType(dataFlowAnalyzer.checkStatementType(property, context))
|
||||
}
|
||||
|
||||
private fun resolveLocalVariableDescriptor(
|
||||
scope: LexicalScope,
|
||||
variable: KtVariableDeclaration,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
trace: BindingTrace
|
||||
): VariableDescriptor {
|
||||
val containingDeclaration = scope.ownerDescriptor
|
||||
val result: VariableDescriptor
|
||||
val type: KotlinType
|
||||
if (KtPsiUtil.isScriptDeclaration(variable)) {
|
||||
val propertyDescriptor = PropertyDescriptorImpl.create(
|
||||
containingDeclaration,
|
||||
annotationResolver.resolveAnnotationsWithArguments(scope, variable.modifierList, trace),
|
||||
Modality.FINAL,
|
||||
Visibilities.INTERNAL,
|
||||
variable.isVar,
|
||||
KtPsiUtil.safeName(variable.name),
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
variable.toSourceElement(),
|
||||
/* lateInit = */ false,
|
||||
/* isConst = */ false
|
||||
)
|
||||
// For a local variable the type must not be deferred
|
||||
type = variableTypeResolver.process(propertyDescriptor, scope, variable, dataFlowInfo, false, trace)
|
||||
|
||||
val receiverParameter = (containingDeclaration as ScriptDescriptor).thisAsReceiverParameter
|
||||
propertyDescriptor.setType(type, emptyList<TypeParameterDescriptor>(), receiverParameter, null as? KotlinType)
|
||||
initializeWithDefaultGetterSetter(propertyDescriptor)
|
||||
trace.record(BindingContext.VARIABLE, variable, propertyDescriptor)
|
||||
result = propertyDescriptor
|
||||
}
|
||||
else {
|
||||
val variableDescriptor = resolveLocalVariableDescriptorWithType(scope, variable, null, trace)
|
||||
// For a local variable the type must not be deferred
|
||||
type = variableTypeResolver.process(variableDescriptor, scope, variable, dataFlowInfo, false, trace)
|
||||
variableDescriptor.setOutType(type)
|
||||
result = variableDescriptor
|
||||
}
|
||||
// Type annotations also should be resolved
|
||||
ForceResolveUtil.forceResolveAllContents(type.annotations)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun initializeWithDefaultGetterSetter(propertyDescriptor: PropertyDescriptorImpl) {
|
||||
var getter = propertyDescriptor.getter
|
||||
if (getter == null && !Visibilities.isPrivate(propertyDescriptor.visibility)) {
|
||||
getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
|
||||
getter.initialize(propertyDescriptor.type)
|
||||
}
|
||||
|
||||
var setter = propertyDescriptor.setter
|
||||
if (setter == null && propertyDescriptor.isVar) {
|
||||
setter = DescriptorFactory.createDefaultSetter(propertyDescriptor, Annotations.EMPTY)
|
||||
}
|
||||
propertyDescriptor.initialize(getter, setter)
|
||||
}
|
||||
|
||||
internal fun resolveLocalVariableDescriptorWithType(
|
||||
scope: LexicalScope,
|
||||
variable: KtVariableDeclaration,
|
||||
type: KotlinType?,
|
||||
trace: BindingTrace
|
||||
): LocalVariableDescriptor {
|
||||
val variableDescriptor = LocalVariableDescriptor(
|
||||
scope.ownerDescriptor,
|
||||
annotationResolver.resolveAnnotationsWithArguments(scope, variable.modifierList, trace),
|
||||
KtPsiUtil.safeName(variable.name),
|
||||
type,
|
||||
variable.isVar,
|
||||
variable.toSourceElement()
|
||||
)
|
||||
trace.record(BindingContext.VARIABLE, variable, variableDescriptor)
|
||||
return variableDescriptor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.VariableDescriptorWithInitializerImpl
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.VARIABLE_WITH_NO_TYPE_NO_INITIALIZER
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtVariableDeclaration
|
||||
import org.jetbrains.kotlin.resolve.DescriptorResolver.transformAnonymousTypeIfNeeded
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.DeferredType
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
|
||||
|
||||
class VariableTypeResolver(
|
||||
private val storageManager: StorageManager,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val typeResolver: TypeResolver,
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||
private val delegatedPropertyResolver: DelegatedPropertyResolver
|
||||
) {
|
||||
|
||||
fun process(
|
||||
variableDescriptor: VariableDescriptorWithInitializerImpl,
|
||||
scopeForInitializer: LexicalScope,
|
||||
variable: KtVariableDeclaration,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
notLocal: Boolean,
|
||||
trace: BindingTrace
|
||||
): KotlinType {
|
||||
val propertyTypeRef = variable.typeReference
|
||||
|
||||
val hasDelegate = variable is KtProperty && variable.hasDelegateExpression()
|
||||
if (propertyTypeRef == null) {
|
||||
if (!variable.hasInitializer()) {
|
||||
if (hasDelegate && variableDescriptor is PropertyDescriptor) {
|
||||
val property = variable as KtProperty
|
||||
if (property.hasDelegateExpression()) {
|
||||
return DeferredType.createRecursionIntolerant(
|
||||
storageManager,
|
||||
trace
|
||||
) {
|
||||
resolveDelegatedPropertyType(property, variableDescriptor, scopeForInitializer,
|
||||
property.delegateExpression!!, dataFlowInfo, trace)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!notLocal) {
|
||||
trace.report(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.on(variable))
|
||||
}
|
||||
return ErrorUtils.createErrorType("No type, no body")
|
||||
}
|
||||
else {
|
||||
if (notLocal) {
|
||||
return DeferredType.createRecursionIntolerant(
|
||||
storageManager,
|
||||
trace
|
||||
) {
|
||||
PreliminaryDeclarationVisitor.createForDeclaration(variable, trace)
|
||||
val initializerType = resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace)
|
||||
setConstantForVariableIfNeeded(variableDescriptor, scopeForInitializer, variable, dataFlowInfo, initializerType, trace)
|
||||
transformAnonymousTypeIfNeeded(variableDescriptor, variable, initializerType, trace)
|
||||
}
|
||||
}
|
||||
else {
|
||||
val initializerType = resolveInitializerType(scopeForInitializer, variable.initializer!!, dataFlowInfo, trace)
|
||||
setConstantForVariableIfNeeded(variableDescriptor, scopeForInitializer, variable, dataFlowInfo, initializerType, trace)
|
||||
return initializerType
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val type = typeResolver.resolveType(scopeForInitializer, propertyTypeRef, trace, true)
|
||||
setConstantForVariableIfNeeded(variableDescriptor, scopeForInitializer, variable, dataFlowInfo, type, trace)
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
private fun setConstantForVariableIfNeeded(
|
||||
variableDescriptor: VariableDescriptorWithInitializerImpl,
|
||||
scope: LexicalScope,
|
||||
variable: KtVariableDeclaration,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
variableType: KotlinType,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
if (!DescriptorUtils.shouldRecordInitializerForProperty(variableDescriptor, variableType)) return
|
||||
|
||||
if (!variable.hasInitializer()) return
|
||||
|
||||
variableDescriptor.setCompileTimeInitializer(
|
||||
storageManager.createRecursionTolerantNullableLazyValue(
|
||||
{
|
||||
val initializer = variable.initializer
|
||||
val initializerType = expressionTypingServices.safeGetType(scope, initializer!!, variableType, dataFlowInfo, trace)
|
||||
val constant = constantExpressionEvaluator.evaluateExpression(initializer, trace, initializerType)
|
||||
?: return@createRecursionTolerantNullableLazyValue null
|
||||
|
||||
if (constant.usesNonConstValAsConstant && variableDescriptor.isConst) {
|
||||
trace.report(Errors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION.on(initializer))
|
||||
}
|
||||
|
||||
constant.toConstantValue(initializerType)
|
||||
},
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun resolveDelegatedPropertyType(
|
||||
property: KtProperty,
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
scopeForInitializer: LexicalScope,
|
||||
delegateExpression: KtExpression,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
trace: BindingTrace
|
||||
): KotlinType {
|
||||
val type = delegatedPropertyResolver.resolveDelegateExpression(
|
||||
delegateExpression, property, propertyDescriptor, scopeForInitializer, trace, dataFlowInfo)
|
||||
|
||||
if (type != null) {
|
||||
val delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForInitializer, propertyDescriptor)
|
||||
val getterReturnType = delegatedPropertyResolver.getDelegatedPropertyGetMethodReturnType(propertyDescriptor, delegateExpression, type, trace, delegateFunctionsScope)
|
||||
if (getterReturnType != null) {
|
||||
return getterReturnType
|
||||
}
|
||||
}
|
||||
return ErrorUtils.createErrorType("Type from delegate")
|
||||
}
|
||||
|
||||
private fun resolveInitializerType(
|
||||
scope: LexicalScope,
|
||||
initializer: KtExpression,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
trace: BindingTrace
|
||||
): KotlinType {
|
||||
return expressionTypingServices.safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo, trace)
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorResolver
|
||||
import org.jetbrains.kotlin.resolve.LocalVariableResolver
|
||||
import org.jetbrains.kotlin.resolve.TypeResolver
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.createComponentName
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope
|
||||
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
|
||||
class DestructuringDeclarationResolver(
|
||||
private val fakeCallResolver: FakeCallResolver,
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
private val localVariableResolver: LocalVariableResolver,
|
||||
private val typeResolver: TypeResolver,
|
||||
private val symbolUsageValidator: SymbolUsageValidator
|
||||
) {
|
||||
@@ -72,7 +72,7 @@ class DestructuringDeclarationResolver(
|
||||
if (componentType == null) {
|
||||
componentType = ErrorUtils.createErrorType("$componentName() return type")
|
||||
}
|
||||
val variableDescriptor = descriptorResolver.resolveLocalVariableDescriptorWithType(writableScope, entry, componentType, context.trace)
|
||||
val variableDescriptor = localVariableResolver.resolveLocalVariableDescriptorWithType(writableScope, entry, componentType, context.trace)
|
||||
|
||||
ExpressionTypingUtils.checkVariableShadowing(writableScope, context.trace, variableDescriptor)
|
||||
|
||||
|
||||
+7
@@ -56,6 +56,8 @@ public class ExpressionTypingComponents {
|
||||
/*package*/ Iterable<CallChecker> callCheckers;
|
||||
/*package*/ IdentifierChecker identifierChecker;
|
||||
/*package*/ DeclarationsCheckerBuilder declarationsCheckerBuilder;
|
||||
/*package*/ LocalVariableResolver localVariableResolver;
|
||||
|
||||
|
||||
@Inject
|
||||
public void setGlobalContext(@NotNull GlobalContext globalContext) {
|
||||
@@ -181,4 +183,9 @@ public class ExpressionTypingComponents {
|
||||
public void setDeclarationsCheckerBuilder(@NotNull DeclarationsCheckerBuilder declarationsCheckerBuilder) {
|
||||
this.declarationsCheckerBuilder = declarationsCheckerBuilder;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLocalVariableResolver(@NotNull LocalVariableResolver localVariableResolver) {
|
||||
this.localVariableResolver = localVariableResolver;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-57
@@ -26,8 +26,9 @@ import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||
@@ -102,61 +103,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
||||
|
||||
@Override
|
||||
public KotlinTypeInfo visitProperty(@NotNull KtProperty property, ExpressionTypingContext typingContext) {
|
||||
ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT).replaceScope(scope);
|
||||
KtTypeReference receiverTypeRef = property.getReceiverTypeReference();
|
||||
if (receiverTypeRef != null) {
|
||||
context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef));
|
||||
}
|
||||
|
||||
KtPropertyAccessor getter = property.getGetter();
|
||||
if (getter != null) {
|
||||
context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter));
|
||||
}
|
||||
|
||||
KtPropertyAccessor setter = property.getSetter();
|
||||
if (setter != null) {
|
||||
context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
|
||||
}
|
||||
|
||||
KtExpression delegateExpression = property.getDelegateExpression();
|
||||
if (delegateExpression != null) {
|
||||
components.expressionTypingServices.getTypeInfo(delegateExpression, context);
|
||||
context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate()));
|
||||
}
|
||||
|
||||
VariableDescriptor propertyDescriptor = components.descriptorResolver.
|
||||
resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace);
|
||||
KtExpression initializer = property.getInitializer();
|
||||
KotlinTypeInfo typeInfo;
|
||||
if (initializer != null) {
|
||||
KotlinType outType = propertyDescriptor.getType();
|
||||
typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
|
||||
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
|
||||
KotlinType type = typeInfo.getType();
|
||||
// At this moment we do not take initializer value into account if type is given for a property
|
||||
// We can comment first part of this condition to take them into account, like here: var s: String? = "xyz"
|
||||
// In this case s will be not-nullable until it is changed
|
||||
if (property.getTypeReference() == null && type != null) {
|
||||
DataFlowValue variableDataFlowValue = DataFlowValueFactory.createDataFlowValueForProperty(
|
||||
property, propertyDescriptor, context.trace.getBindingContext(),
|
||||
DescriptorUtils.getContainingModuleOrNull(scope.getOwnerDescriptor()));
|
||||
DataFlowValue initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context);
|
||||
// We cannot say here anything new about initializerDataFlowValue
|
||||
// except it has the same value as variableDataFlowValue
|
||||
typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.assign(variableDataFlowValue, initializerDataFlowValue));
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeInfo = TypeInfoFactoryKt.noTypeInfo(context);
|
||||
}
|
||||
|
||||
ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, propertyDescriptor);
|
||||
|
||||
scope.addVariableDescriptor(propertyDescriptor);
|
||||
DeclarationsCheckerKt.checkTypeReferences(property, context.trace);
|
||||
components.modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor);
|
||||
components.identifierChecker.checkDeclaration(property, context.trace);
|
||||
return typeInfo.replaceType(components.dataFlowAnalyzer.checkStatementType(property, context));
|
||||
return components.localVariableResolver.process(property, typingContext, scope, facade);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user