Delegated Properties: Analysis adjustments for local delegated properties support

This commit is contained in:
Dotlin
2016-02-07 17:43:15 +03:00
committed by Mikhael Bogdanov
parent 9bfb226948
commit fa523b9af4
32 changed files with 423 additions and 88 deletions
@@ -1055,6 +1055,9 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
// We do not want to have getDeferredValue(delegate) here, because delegate value will be read anyway later
visitAssignment(property, getDeferredValue(null), property)
generateInstructions(delegate)
if (property.isLocal) {
generateInitializer(property, createSyntheticValue(property, MagicKind.FAKE_INITIALIZER));
}
if (builder.getBoundValue(delegate) != null) {
createSyntheticValue(property, MagicKind.VALUE_CONSUMER, delegate)
}
@@ -0,0 +1,51 @@
/*
* 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.descriptors.impl
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.VariableAccessorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
sealed class LocalVariableAccessorDescriptor(
override val correspondingVariable: LocalVariableDescriptor,
isGetter: Boolean
) : SimpleFunctionDescriptorImpl(
correspondingVariable.containingDeclaration,
null,
Annotations.EMPTY,
Name.special((if (isGetter) "<get-" else "<set-") + correspondingVariable.name + ">"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE
), VariableAccessorDescriptor {
class Getter(correspondingVariable: LocalVariableDescriptor) : LocalVariableAccessorDescriptor(correspondingVariable, true)
class Setter(correspondingVariable: LocalVariableDescriptor) : LocalVariableAccessorDescriptor(correspondingVariable, false)
init {
val valueParameters =
if (isGetter) emptyList() else createValueParameter(Name.identifier("value"), correspondingVariable.type).singletonList()
initialize(null, null, emptyList(), valueParameters, correspondingVariable.type, null, Visibilities.LOCAL)
}
private fun createValueParameter(name: Name, type: KotlinType): ValueParameterDescriptorImpl {
return ValueParameterDescriptorImpl(this, null, 0, Annotations.EMPTY, name, type, false, false, false, null, SourceElement.NO_SOURCE)
}
}
@@ -24,16 +24,33 @@ import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeSubstitutor;
public class LocalVariableDescriptor extends VariableDescriptorWithInitializerImpl {
public class LocalVariableDescriptor extends VariableDescriptorWithInitializerImpl implements VariableDescriptorWithAccessors {
private final boolean withAccessors;
private VariableAccessorDescriptor getter;
private VariableAccessorDescriptor setter;
public LocalVariableDescriptor(
@NotNull DeclarationDescriptor containingDeclaration,
@NotNull Annotations annotations,
@NotNull Name name,
@Nullable KotlinType type,
boolean mutable,
boolean withAccessors,
@NotNull SourceElement source
) {
super(containingDeclaration, annotations, name, type, mutable, source);
this.withAccessors = withAccessors;
}
@Override
public void setOutType(KotlinType outType) {
super.setOutType(outType);
if (withAccessors) {
this.getter = new LocalVariableAccessorDescriptor.Getter(this);
if (isVar()) {
this.setter = new LocalVariableAccessorDescriptor.Setter(this);
}
}
}
@NotNull
@@ -53,4 +70,16 @@ public class LocalVariableDescriptor extends VariableDescriptorWithInitializerIm
public Visibility getVisibility() {
return Visibilities.LOCAL;
}
@Nullable
@Override
public VariableAccessorDescriptor getGetter() {
return getter;
}
@Nullable
@Override
public VariableAccessorDescriptor getSetter() {
return setter;
}
}
@@ -29,7 +29,7 @@ class SyntheticFieldDescriptor private constructor(
accessorDescriptor: PropertyAccessorDescriptor,
property: KtProperty
): LocalVariableDescriptor(accessorDescriptor, Annotations.EMPTY, SyntheticFieldDescriptor.NAME,
propertyDescriptor.type, propertyDescriptor.isVar, property.toSourceElement()) {
propertyDescriptor.type, propertyDescriptor.isVar, false, property.toSourceElement()) {
constructor(accessorDescriptor: PropertyAccessorDescriptor,
property: KtProperty): this(accessorDescriptor.correspondingProperty, accessorDescriptor, property)
@@ -385,7 +385,7 @@ public interface Errors {
DiagnosticFactory0<KtPropertyDelegate> ABSTRACT_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyAccessor> ACCESSOR_FOR_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyDelegate> DELEGATED_PROPERTY_IN_INTERFACE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyDelegate> LOCAL_VARIABLE_WITH_DELEGATE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtPropertyDelegate> SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtProperty> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
@@ -214,7 +214,7 @@ public class DefaultErrorMessages {
MAP.put(ABSTRACT_DELEGATED_PROPERTY, "Delegated property cannot be abstract");
MAP.put(ACCESSOR_FOR_DELEGATED_PROPERTY, "Delegated property cannot have accessors with non-default implementations");
MAP.put(DELEGATED_PROPERTY_IN_INTERFACE, "Delegated properties are not allowed in interfaces");
MAP.put(LOCAL_VARIABLE_WITH_DELEGATE, "Local variables are not allowed to have delegates");
MAP.put(SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE, "Top-level local variables in scripts are not allowed to have delegates");
MAP.put(INAPPLICABLE_LATEINIT_MODIFIER, "''lateinit'' modifier {0}", STRING);
@@ -123,10 +123,10 @@ public interface BindingContext {
WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> LOOP_RANGE_HAS_NEXT_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<KtExpression, ResolvedCall<FunctionDescriptor>> LOOP_RANGE_NEXT_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<PropertyAccessorDescriptor, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<PropertyAccessorDescriptor, Call> DELEGATED_PROPERTY_CALL = Slices.createSimpleSlice();
WritableSlice<VariableAccessorDescriptor, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<VariableAccessorDescriptor, Call> DELEGATED_PROPERTY_CALL = Slices.createSimpleSlice();
WritableSlice<PropertyDescriptor, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_PD_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<VariableDescriptorWithAccessors, ResolvedCall<FunctionDescriptor>> DELEGATED_PROPERTY_PD_RESOLVED_CALL = Slices.createSimpleSlice();
WritableSlice<KtDestructuringDeclarationEntry, ResolvedCall<FunctionDescriptor>> COMPONENT_RESOLVED_CALL = Slices.createSimpleSlice();
@@ -696,34 +696,12 @@ public class BodyResolver {
@NotNull KtExpression delegateExpression,
@NotNull LexicalScope propertyHeaderScope
) {
KtPropertyAccessor getter = property.getGetter();
if (getter != null && getter.hasBody()) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter));
}
KtPropertyAccessor setter = property.getSetter();
if (setter != null && setter.hasBody()) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(setter));
}
LexicalScope delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(propertyHeaderScope, propertyDescriptor);
LexicalScope initializerScope = ScopeUtils.makeScopeForPropertyInitializer(propertyHeaderScope, propertyDescriptor);
KotlinType delegateType = delegatedPropertyResolver.resolveDelegateExpression(
delegateExpression, property, propertyDescriptor, initializerScope, trace,
outerDataFlowInfo);
delegatedPropertyResolver.resolveDelegatedPropertyGetMethod(propertyDescriptor, delegateExpression, delegateType,
trace, delegateFunctionsScope);
if (property.isVar()) {
delegatedPropertyResolver.resolveDelegatedPropertySetMethod(propertyDescriptor, delegateExpression, delegateType,
trace, delegateFunctionsScope);
}
delegatedPropertyResolver.resolveDelegatedPropertyPDMethod(propertyDescriptor, delegateExpression, delegateType,
trace, delegateFunctionsScope);
delegatedPropertyResolver.resolvePropertyDelegate(outerDataFlowInfo,
property,
propertyDescriptor,
delegateExpression,
propertyHeaderScope,
trace);
}
private void resolvePropertyInitializer(
@@ -400,6 +400,14 @@ class DeclarationsChecker(
exposedChecker.checkProperty(property, propertyDescriptor)
checkPropertyTypeParametersAreUsedInReceiverType(propertyDescriptor)
checkImplicitCallableType(property, propertyDescriptor)
checkDelegatedPropertyInScript(property)
}
private fun checkDelegatedPropertyInScript(property: KtProperty) {
val delegate = property.delegate
if (delegate != null && KtPsiUtil.isScriptDeclaration(property)) {
trace.report(SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE.on(delegate))
}
}
private fun checkPropertyTypeParametersAreUsedInReceiverType(descriptor: PropertyDescriptor) {
@@ -85,48 +85,93 @@ public class DelegatedPropertyResolver {
this.expressionTypingServices = expressionTypingServices;
}
public void resolvePropertyDelegate(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtProperty property,
@NotNull VariableDescriptorWithAccessors variableDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull LexicalScope propertyHeaderScope,
@NotNull BindingTrace trace
) {
KtPropertyAccessor getter = property.getGetter();
if (getter != null && getter.hasBody()) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter));
}
KtPropertyAccessor setter = property.getSetter();
if (setter != null && setter.hasBody()) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(setter));
}
LexicalScope delegateFunctionsScope;
LexicalScope initializerScope;
if (variableDescriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(propertyHeaderScope, propertyDescriptor);
initializerScope = ScopeUtils.makeScopeForPropertyInitializer(propertyHeaderScope, propertyDescriptor);
}
else {
delegateFunctionsScope = initializerScope = propertyHeaderScope;
}
KotlinType delegateType = resolveDelegateExpression(delegateExpression,
property,
variableDescriptor,
initializerScope,
trace,
outerDataFlowInfo);
resolveDelegatedPropertyGetMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope);
if (property.isVar()) {
resolveDelegatedPropertySetMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope);
}
resolveDelegatedPropertyPDMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope);
}
@Nullable
public KotlinType getDelegatedPropertyGetMethodReturnType(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull VariableDescriptorWithAccessors variableDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull KotlinType delegateType,
@NotNull BindingTrace trace,
@NotNull LexicalScope delegateFunctionsScope
) {
resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, true);
resolveDelegatedPropertyConventionMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, true);
ResolvedCall<FunctionDescriptor> resolvedCall =
trace.getBindingContext().get(DELEGATED_PROPERTY_RESOLVED_CALL, propertyDescriptor.getGetter());
trace.getBindingContext().get(DELEGATED_PROPERTY_RESOLVED_CALL, variableDescriptor.getGetter());
return resolvedCall != null ? resolvedCall.getResultingDescriptor().getReturnType() : null;
}
public void resolveDelegatedPropertyGetMethod(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull VariableDescriptorWithAccessors variableDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull KotlinType delegateType,
@NotNull BindingTrace trace,
@NotNull LexicalScope delegateFunctionsScope
) {
KotlinType returnType = getDelegatedPropertyGetMethodReturnType(
propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope);
KotlinType propertyType = propertyDescriptor.getType();
variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope);
KotlinType propertyType = variableDescriptor.getType();
/* Do not check return type of get() method of delegate for properties with DeferredType because property type is taken from it */
if (!(propertyType instanceof DeferredType) && returnType != null && !KotlinTypeChecker.DEFAULT.isSubtypeOf(returnType, propertyType)) {
Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, propertyDescriptor.getGetter());
assert call != null : "Call should exists for " + propertyDescriptor.getGetter();
Call call = trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, variableDescriptor.getGetter());
assert call != null : "Call should exists for " + variableDescriptor.getGetter();
trace.report(DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH
.on(delegateExpression, renderCall(call, trace.getBindingContext()), propertyDescriptor.getType(), returnType));
.on(delegateExpression, renderCall(call, trace.getBindingContext()), variableDescriptor.getType(), returnType));
}
}
public void resolveDelegatedPropertySetMethod(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull VariableDescriptorWithAccessors variableDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull KotlinType delegateType,
@NotNull BindingTrace trace,
@NotNull LexicalScope delegateFunctionsScope
) {
resolveDelegatedPropertyConventionMethod(propertyDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, false);
resolveDelegatedPropertyConventionMethod(variableDescriptor, delegateExpression, delegateType, trace, delegateFunctionsScope, false);
}
@NotNull
@@ -135,7 +180,7 @@ public class DelegatedPropertyResolver {
}
public void resolveDelegatedPropertyPDMethod(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull VariableDescriptorWithAccessors variableDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull KotlinType delegateType,
@NotNull BindingTrace trace,
@@ -168,19 +213,19 @@ public class DelegatedPropertyResolver {
return;
}
trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, propertyDescriptor, functionResults.getResultingCall());
trace.record(DELEGATED_PROPERTY_PD_RESOLVED_CALL, variableDescriptor, functionResults.getResultingCall());
}
/* Resolve getValue() or setValue() methods from delegate */
private void resolveDelegatedPropertyConventionMethod(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull VariableDescriptorWithAccessors propertyDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull KotlinType delegateType,
@NotNull BindingTrace trace,
@NotNull LexicalScope delegateFunctionsScope,
boolean isGet
) {
PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
VariableAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText();
if (trace.getBindingContext().get(DELEGATED_PROPERTY_CALL, accessor) != null) return;
@@ -229,7 +274,7 @@ public class DelegatedPropertyResolver {
/* Resolve getValue() or setValue() methods from delegate */
public OverloadResolutionResults<FunctionDescriptor> getDelegatedPropertyConventionMethod(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull VariableDescriptorWithAccessors propertyDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull KotlinType delegateType,
@NotNull BindingTrace trace,
@@ -237,7 +282,7 @@ public class DelegatedPropertyResolver {
boolean isGet,
boolean isComplete
) {
PropertyAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
VariableAccessorDescriptor accessor = isGet ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter();
assert accessor != null : "Delegated property should have getter/setter " + propertyDescriptor + " " + delegateExpression.getText();
KotlinType expectedType = isComplete && isGet && !(propertyDescriptor.getType() instanceof DeferredType)
@@ -326,7 +371,7 @@ public class DelegatedPropertyResolver {
public KotlinType resolveDelegateExpression(
@NotNull KtExpression delegateExpression,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull VariableDescriptorWithAccessors variableDescriptor,
@NotNull LexicalScope scopeForDelegate,
@NotNull BindingTrace trace,
@NotNull DataFlowInfo dataFlowInfo
@@ -334,7 +379,7 @@ public class DelegatedPropertyResolver {
TemporaryBindingTrace traceToResolveDelegatedProperty = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property");
KtExpression calleeExpression = CallUtilKt.getCalleeExpressionIfAny(delegateExpression);
ConstraintSystemCompleter completer = createConstraintSystemCompleter(
property, propertyDescriptor, delegateExpression, scopeForDelegate, trace);
property, variableDescriptor, delegateExpression, scopeForDelegate, trace);
if (calleeExpression != null) {
traceToResolveDelegatedProperty.record(CONSTRAINT_SYSTEM_COMPLETER, calleeExpression, completer);
}
@@ -352,13 +397,13 @@ public class DelegatedPropertyResolver {
@NotNull
private ConstraintSystemCompleter createConstraintSystemCompleter(
@NotNull KtProperty property,
@NotNull final PropertyDescriptor propertyDescriptor,
@NotNull final VariableDescriptorWithAccessors variableDescriptor,
@NotNull final KtExpression delegateExpression,
@NotNull LexicalScope scopeForDelegate,
@NotNull final BindingTrace trace
) {
final LexicalScope delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForDelegate, propertyDescriptor);
final KotlinType expectedType = property.getTypeReference() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
final LexicalScope delegateFunctionsScope = ScopeUtils.makeScopeForDelegateConventionFunctions(scopeForDelegate, variableDescriptor);
final KotlinType expectedType = property.getTypeReference() != null ? variableDescriptor.getType() : NO_EXPECTED_TYPE;
return new ConstraintSystemCompleter() {
@Override
public void completeConstraintSystem(
@@ -375,7 +420,7 @@ public class DelegatedPropertyResolver {
TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods");
OverloadResolutionResults<FunctionDescriptor>
getMethodResults = getDelegatedPropertyConventionMethod(
propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
true, false
);
@@ -390,16 +435,16 @@ public class DelegatedPropertyResolver {
}
addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor);
}
if (!propertyDescriptor.isVar()) return;
if (!variableDescriptor.isVar()) return;
// For the case: 'val v by d' (no declared type).
// When we add a constraint for 'set' method for delegated expression 'd' we use a type of the declared variable 'v'.
// But if the type isn't known yet, the constraint shouldn't be added (we try to infer the type of 'v' here as well).
if (propertyDescriptor.getReturnType() instanceof DeferredType) return;
if (variableDescriptor.getReturnType() instanceof DeferredType) return;
OverloadResolutionResults<FunctionDescriptor>
setMethodResults = getDelegatedPropertyConventionMethod(
propertyDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
variableDescriptor, delegateExpression, returnType, traceToResolveConventionMethods, delegateFunctionsScope,
false, false
);
@@ -432,8 +477,8 @@ public class DelegatedPropertyResolver {
TypeSubstitutor typeVariableSubstitutor,
FunctionDescriptor resultingDescriptor
) {
ReceiverParameterDescriptor extensionReceiver = propertyDescriptor.getExtensionReceiverParameter();
ReceiverParameterDescriptor dispatchReceiver = propertyDescriptor.getDispatchReceiverParameter();
ReceiverParameterDescriptor extensionReceiver = variableDescriptor.getExtensionReceiverParameter();
ReceiverParameterDescriptor dispatchReceiver = variableDescriptor.getDispatchReceiverParameter();
KotlinType typeOfThis =
extensionReceiver != null ? extensionReceiver.getType() :
dispatchReceiver != null ? dispatchReceiver.getType() :
@@ -655,6 +655,7 @@ public class DescriptorResolver {
KtPsiUtil.safeName(parameter.getName()),
type,
false,
false,
KotlinSourceElementKt.toSourceElement(parameter)
);
trace.record(BindingContext.VALUE_PARAMETER, parameter, variableDescriptor);
@@ -35,12 +35,12 @@ 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
private val variableTypeResolver: VariableTypeResolver,
private val delegatedPropertyResolver: DelegatedPropertyResolver
) {
fun process(
@@ -65,13 +65,18 @@ class LocalVariableResolver(
context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter))
}
val propertyDescriptor = resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace)
val delegateExpression = property.delegateExpression
if (delegateExpression != null) {
expressionTypingServices.getTypeInfo(delegateExpression, context)
context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.delegate!!))
if (delegateExpression != null && propertyDescriptor is VariableDescriptorWithAccessors) {
delegatedPropertyResolver.resolvePropertyDelegate(typingContext.dataFlowInfo,
property,
propertyDescriptor,
delegateExpression,
typingContext.scope,
typingContext.trace);
}
val propertyDescriptor = resolveLocalVariableDescriptor(scope, property, context.dataFlowInfo, context.trace)
val initializer = property.initializer
var typeInfo: KotlinTypeInfo
if (initializer != null) {
@@ -167,12 +172,14 @@ class LocalVariableResolver(
type: KotlinType?,
trace: BindingTrace
): LocalVariableDescriptor {
val hasDelegate = variable is KtProperty && variable.hasDelegate();
val variableDescriptor = LocalVariableDescriptor(
scope.ownerDescriptor,
annotationResolver.resolveAnnotationsWithArguments(scope, variable.modifierList, trace),
KtPsiUtil.safeName(variable.name),
type,
variable.isVar,
hasDelegate,
variable.toSourceElement()
)
trace.record(BindingContext.VARIABLE, variable, variableDescriptor)
@@ -202,7 +202,7 @@ private fun bindFunctionReference(expression: KtCallableReferenceExpression, typ
private fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) {
val localVariable = LocalVariableDescriptor(context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"),
referenceType, /* mutable = */ false, expression.toSourceElement())
referenceType, /* mutable = */ false, false, expression.toSourceElement())
context.trace.record(BindingContext.VARIABLE, expression, localVariable)
}
@@ -60,7 +60,7 @@ public class ExpressionTypingComponents {
/*package*/ DeclarationsCheckerBuilder declarationsCheckerBuilder;
/*package*/ LocalVariableResolver localVariableResolver;
/*package*/ LookupTracker lookupTracker;
/*package*/ DelegatedPropertyResolver delegatedPropertyResolver;
@Inject
public void setGlobalContext(@NotNull GlobalContext globalContext) {
@@ -201,4 +201,9 @@ public class ExpressionTypingComponents {
public void setLookupTracker(@NotNull LookupTracker lookupTracker) {
this.lookupTracker = lookupTracker;
}
@Inject
public void setDelegatedPropertyResolver(DelegatedPropertyResolver delegatedPropertyResolver) {
this.delegatedPropertyResolver = delegatedPropertyResolver;
}
}
@@ -20,10 +20,7 @@ import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.utils.Printer;
public final class ScopeUtils {
@@ -69,10 +66,10 @@ public final class ScopeUtils {
@NotNull
public static LexicalScope makeScopeForDelegateConventionFunctions(
@NotNull LexicalScope parent,
@NotNull PropertyDescriptor propertyDescriptor
@NotNull VariableDescriptorWithAccessors variableDescriptor
) {
// todo: very strange scope!
return new LexicalScopeImpl(parent, propertyDescriptor, true, propertyDescriptor.getExtensionReceiverParameter(),
return new LexicalScopeImpl(parent, variableDescriptor, true, variableDescriptor.getExtensionReceiverParameter(),
LexicalScopeKind.PROPERTY_DELEGATE_METHOD
);
}
@@ -0,0 +1,60 @@
== Delegate ==
class Delegate {
operator fun getValue(t: Any?, p: KProperty<*>): Int = 1
}
---------------------
L0:
1 <START>
L1:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== getValue ==
operator fun getValue(t: Any?, p: KProperty<*>): Int = 1
---------------------
L0:
1 <START>
v(t: Any?)
magic[FAKE_INITIALIZER](t: Any?) -> <v0>
w(t|<v0>)
v(p: KProperty<*>)
magic[FAKE_INITIALIZER](p: KProperty<*>) -> <v1>
w(p|<v1>)
r(1) -> <v2>
ret(*|<v2>) L1
L1:
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
== foo ==
fun foo(): Int {
val prop: Int by Delegate()
return prop
}
---------------------
L0:
1 <START>
2 mark({ val prop: Int by Delegate() return prop })
v(val prop: Int by Delegate())
magic[UNRECOGNIZED_WRITE_RHS](val prop: Int by Delegate()) -> <v0>
w(prop|<v0>)
mark(Delegate())
call(Delegate(), <init>) -> <v1>
magic[FAKE_INITIALIZER](val prop: Int by Delegate()) -> <v2>
w(prop|<v2>)
magic[VALUE_CONSUMER](val prop: Int by Delegate()|<v1>) -> <v3>
r(prop) -> <v4>
ret(*|<v4>) L1
L1:
1 <END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
@@ -0,0 +1,10 @@
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(t: Any?, p: KProperty<*>): Int = 1
}
fun foo(): Int {
val prop: Int by Delegate()
return prop
}
@@ -0,0 +1,27 @@
== Delegate ==
class Delegate {
operator fun getValue(t: Any?, p: KProperty<*>): Int = 1
}
---------------------
=====================
== getValue ==
operator fun getValue(t: Any?, p: KProperty<*>): Int = 1
---------------------
<v0>: * NEW: magic[FAKE_INITIALIZER](t: Any?) -> <v0>
<v1>: {<: KProperty<*>} NEW: magic[FAKE_INITIALIZER](p: KProperty<*>) -> <v1>
1 <v2>: Int NEW: r(1) -> <v2>
=====================
== foo ==
fun foo(): Int {
val prop: Int by Delegate()
return prop
}
---------------------
<v0>: Int NEW: magic[UNRECOGNIZED_WRITE_RHS](val prop: Int by Delegate()) -> <v0>
<v2>: Int NEW: magic[FAKE_INITIALIZER](val prop: Int by Delegate()) -> <v2>
<v3>: * NEW: magic[VALUE_CONSUMER](val prop: Int by Delegate()|<v1>) -> <v3>
Delegate() <v1>: * NEW: call(Delegate(), <init>) -> <v1>
prop <v4>: Int NEW: r(prop) -> <v4>
return prop !<v5>: *
{ val prop: Int by Delegate() return prop } !<v5>: * COPY
=====================
@@ -3,13 +3,13 @@
import kotlin.reflect.KProperty
class Local {
fun foo() {
val a: Int <!LOCAL_VARIABLE_WITH_DELEGATE!>by Delegate()<!>
}
fun foo() {
val a: Int by Delegate()
}
}
class Delegate {
fun getValue(t: Any?, p: KProperty<*>): Int {
return 1
}
operator fun getValue(t: Any?, p: KProperty<*>): Int {
return 1
}
}
@@ -3,7 +3,7 @@ package
public final class Delegate {
public constructor Delegate()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun getValue(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): kotlin.Int
public final operator fun getValue(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,20 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_VARIABLE
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(t: Any?, p: KProperty<*>): Int {
return 1
}
}
val a: Int <!SCRIPT_TOP_LEVEL_LOCAL_VARIABLE_WITH_DELEGATE!>by Delegate()<!>
class Foo {
val a: Int by Delegate()
}
fun foo() {
val a: Int by Delegate()
}
@@ -0,0 +1,27 @@
package
public final class TopLevelVariable {
public constructor TopLevelVariable(/*0*/ args: kotlin.Array<kotlin.String>)
public final val a: kotlin.Int
public final val args: kotlin.Array<kotlin.String>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final class Delegate {
public constructor Delegate()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final operator fun getValue(/*0*/ t: kotlin.Any?, /*1*/ p: kotlin.reflect.KProperty<*>): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Foo {
public constructor Foo()
public final val a: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -474,6 +474,12 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest {
doTest(fileName);
}
@TestMetadata("localDelegatedVal.kt")
public void testLocalDelegatedVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/local/localDelegatedVal.kt");
doTest(fileName);
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/local/localFunction.kt");
@@ -476,6 +476,12 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest {
doTest(fileName);
}
@TestMetadata("localDelegatedVal.kt")
public void testLocalDelegatedVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/local/localDelegatedVal.kt");
doTest(fileName);
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cfg/declarations/local/localFunction.kt");
@@ -19641,6 +19641,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/script/SimpleScript.kts");
doTest(fileName);
}
@TestMetadata("topLevelVariable.kts")
public void testTopLevelVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/script/topLevelVariable.kts");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/diagnostics")
@@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public interface PropertyAccessorDescriptor extends FunctionDescriptor {
public interface PropertyAccessorDescriptor extends VariableAccessorDescriptor {
boolean isDefault();
@NotNull
@@ -23,10 +23,12 @@ import org.jetbrains.kotlin.types.TypeSubstitutor;
import java.util.Collection;
import java.util.List;
public interface PropertyDescriptor extends VariableDescriptor, CallableMemberDescriptor {
public interface PropertyDescriptor extends VariableDescriptorWithAccessors, CallableMemberDescriptor {
@Override
@Nullable
PropertyGetterDescriptor getGetter();
@Override
@Nullable
PropertySetterDescriptor getSetter();
@@ -0,0 +1,21 @@
/*
* 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.descriptors
public interface VariableAccessorDescriptor : FunctionDescriptor {
val correspondingVariable: VariableDescriptorWithAccessors
}
@@ -0,0 +1,22 @@
/*
* 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.descriptors
public interface VariableDescriptorWithAccessors : VariableDescriptor {
public val getter: VariableAccessorDescriptor?
public val setter: VariableAccessorDescriptor?
}
@@ -132,6 +132,12 @@ public abstract class PropertyAccessorDescriptorImpl extends DeclarationDescript
this.visibility = visibility;
}
@NotNull
@Override
public VariableDescriptorWithAccessors getCorrespondingVariable() {
return correspondingProperty;
}
@Override
@NotNull
public PropertyDescriptor getCorrespondingProperty() {
@@ -1,5 +1,4 @@
// "Create property 'foo'" "true"
// ERROR: Local variables are not allowed to have delegates
// ERROR: Property must be initialized
fun test() {
@@ -1,7 +1,6 @@
import kotlin.properties.ReadOnlyProperty
// "Create property 'foo'" "true"
// ERROR: Local variables are not allowed to have delegates
// ERROR: Property must be initialized
val foo: ReadOnlyProperty<Nothing?, Int>