[PSI, FE, PSI2IR] Use labels for referencing specific receiver

This commit is contained in:
Anastasiya Shadrina
2021-01-18 19:47:07 +07:00
committed by TeamCityServer
parent aaabf5e1ca
commit 1bcaeabd84
54 changed files with 744 additions and 134 deletions
@@ -437,9 +437,9 @@ fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescri
val result = HashSet<String>() val result = HashSet<String>()
if (lambdaOrFun != null) { if (lambdaOrFun != null) {
val label = LabelResolver.getLabelNameIfAny(lambdaOrFun) val label = LabelResolver.getLabelNamesIfAny(lambdaOrFun, addContextReceiverNames = false)
if (label != null) { if (label.isNotEmpty()) {
result.add(label.asString()) result.add(label.single().asString())
} }
} }
@@ -10624,6 +10624,42 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/plusMatrix.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/plusMatrix.kt");
} }
@Test
@TestMetadata("superWithContext.kt")
public void testSuperWithContext() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/superWithContext.kt");
}
@Test
@TestMetadata("thisIdentifierInfo.kt")
public void testThisIdentifierInfo() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisIdentifierInfo.kt");
}
@Test
@TestMetadata("thisWithCustomLabel.kt")
public void testThisWithCustomLabel() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithCustomLabel.kt");
}
@Test
@TestMetadata("thisWithReceiverLabelsClasses.kt")
public void testThisWithReceiverLabelsClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsClasses.kt");
}
@Test
@TestMetadata("thisWithReceiverLabelsFunctions.kt")
public void testThisWithReceiverLabelsFunctions() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.kt");
}
@Test
@TestMetadata("thisWithReceiverLabelsProperties.kt")
public void testThisWithReceiverLabelsProperties() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.kt");
}
@Test @Test
@TestMetadata("typeParameterized.kt") @TestMetadata("typeParameterized.kt")
public void testTypeParameterized() throws Exception { public void testTypeParameterized() throws Exception {
@@ -16168,6 +16168,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testSimpleCall() throws Exception { public void testSimpleCall() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt"); runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt");
} }
@Test
@TestMetadata("this.kt")
public void testThis() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/this.kt");
}
} }
} }
@@ -167,7 +167,7 @@ class SyntheticClassOrObjectDescriptor(
override fun getPrimaryConstructorModifierList(): KtModifierList? = null override fun getPrimaryConstructorModifierList(): KtModifierList? = null
override fun getPrimaryConstructorParameters(): List<KtParameter> = emptyList() override fun getPrimaryConstructorParameters(): List<KtParameter> = emptyList()
override fun getSecondaryConstructors(): List<KtSecondaryConstructor> = emptyList() override fun getSecondaryConstructors(): List<KtSecondaryConstructor> = emptyList()
override fun getContextReceiverTypeReferences(): List<KtTypeReference> = emptyList() override fun getContextReceivers(): List<KtContextReceiver> = emptyList()
override fun getPsiOrParent() = _parent.psiOrParent override fun getPsiOrParent() = _parent.psiOrParent
override fun getParent() = _parent.psiOrParent override fun getParent() = _parent.psiOrParent
@@ -48,6 +48,8 @@ import org.jetbrains.kotlin.util.slicedMap.*;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import static org.jetbrains.kotlin.util.slicedMap.RewritePolicy.DO_NOTHING; import static org.jetbrains.kotlin.util.slicedMap.RewritePolicy.DO_NOTHING;
import static org.jetbrains.kotlin.util.slicedMap.Slices.COMPILE_TIME_VALUE_REWRITE_POLICY; import static org.jetbrains.kotlin.util.slicedMap.Slices.COMPILE_TIME_VALUE_REWRITE_POLICY;
@@ -262,6 +264,7 @@ public interface BindingContext {
.setFurtherLookupSlices(DECLARATIONS_TO_DESCRIPTORS) .setFurtherLookupSlices(DECLARATIONS_TO_DESCRIPTORS)
.build(); .build();
WritableSlice<DeclarationDescriptor, LinkedHashMap<ReceiverParameterDescriptor, String>> DESCRIPTOR_TO_NAMED_RECEIVERS = Slices.createSimpleSlice();
WritableSlice<KtReferenceExpression, PsiElement> LABEL_TARGET = Slices.createSimpleSlice(); WritableSlice<KtReferenceExpression, PsiElement> LABEL_TARGET = Slices.createSimpleSlice();
WritableSlice<KtReferenceExpression, Collection<? extends PsiElement>> AMBIGUOUS_LABEL_TARGET = Slices.createSimpleSlice(); WritableSlice<KtReferenceExpression, Collection<? extends PsiElement>> AMBIGUOUS_LABEL_TARGET = Slices.createSimpleSlice();
WritableSlice<ValueParameterDescriptor, PropertyDescriptor> VALUE_PARAMETER_AS_PROPERTY = Slices.createSimpleSlice(); WritableSlice<ValueParameterDescriptor, PropertyDescriptor> VALUE_PARAMETER_AS_PROPERTY = Slices.createSimpleSlice();
@@ -1023,7 +1023,8 @@ public class BodyResolver {
); );
// Synthetic "field" creation // Synthetic "field" creation
if (functionDescriptor instanceof PropertyAccessorDescriptor && functionDescriptor.getExtensionReceiverParameter() == null) { if (functionDescriptor instanceof PropertyAccessorDescriptor && functionDescriptor.getExtensionReceiverParameter() == null
&& functionDescriptor.getContextReceiverParameters().isEmpty()) {
PropertyAccessorDescriptor accessorDescriptor = (PropertyAccessorDescriptor) functionDescriptor; PropertyAccessorDescriptor accessorDescriptor = (PropertyAccessorDescriptor) functionDescriptor;
KtProperty property = (KtProperty) function.getParent(); KtProperty property = (KtProperty) function.getParent();
SourceElement propertySourceElement = KotlinSourceElementKt.toSourceElement(property); SourceElement propertySourceElement = KotlinSourceElementKt.toSourceElement(property);
@@ -64,13 +64,11 @@ import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*; import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.lexer.KtTokens.*; import static org.jetbrains.kotlin.lexer.KtTokens.*;
import static org.jetbrains.kotlin.resolve.BindingContext.CONSTRUCTOR; import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_ALIAS;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveMemberModalityFromModifiers; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveMemberModalityFromModifiers;
import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
@@ -929,7 +927,6 @@ public class DescriptorResolver {
LexicalScope scopeForDeclarationResolutionWithTypeParameters; LexicalScope scopeForDeclarationResolutionWithTypeParameters;
LexicalScope scopeForInitializerResolutionWithTypeParameters; LexicalScope scopeForInitializerResolutionWithTypeParameters;
KotlinType receiverType = null; KotlinType receiverType = null;
Stream<KotlinType> contextReceiverTypes;
{ {
List<KtTypeParameter> typeParameters = variableDeclaration.getTypeParameters(); List<KtTypeParameter> typeParameters = variableDeclaration.getTypeParameters();
@@ -958,37 +955,25 @@ public class DescriptorResolver {
scopeForDeclarationResolutionWithTypeParameters = writableScopeForDeclarationResolution; scopeForDeclarationResolutionWithTypeParameters = writableScopeForDeclarationResolution;
scopeForInitializerResolutionWithTypeParameters = writableScopeForInitializerResolution; scopeForInitializerResolutionWithTypeParameters = writableScopeForInitializerResolution;
} }
KtTypeReference receiverTypeRef = variableDeclaration.getReceiverTypeReference();
if (receiverTypeRef != null) {
receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true);
}
List<KtTypeReference> contextReceiverTypeRefs = variableDeclaration.getContextReceiverTypeReferences();
for (KtTypeReference contextReceiverTypeRef: contextReceiverTypeRefs) {
typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, contextReceiverTypeRef, trace, true);
}
contextReceiverTypes = contextReceiverTypeRefs.stream()
.map((typeRef) -> typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, typeRef, trace, true));
} }
ReceiverParameterDescriptor receiverDescriptor; LinkedHashMap<ReceiverParameterDescriptor, String> receiverToLabelMap = new LinkedHashMap<>();
if (receiverType != null) {
KtTypeReference receiverTypeRef = variableDeclaration.getReceiverTypeReference();
ReceiverParameterDescriptor receiverDescriptor = null;
if (receiverTypeRef != null) {
receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true);
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, receiverType.getAnnotations(), EnumSet.of(RECEIVER)); AnnotationSplitter splitter = new AnnotationSplitter(storageManager, receiverType.getAnnotations(), EnumSet.of(RECEIVER));
receiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable( receiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER) propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER),
); false);
} receiverToLabelMap.put(receiverDescriptor, receiverTypeRef.nameForReceiverLabel());
else {
receiverDescriptor = null;
} }
List<ReceiverParameterDescriptor> contextReceiverDescriptors = contextReceiverTypes.map((type) -> { List<KtContextReceiver> contextReceivers = variableDeclaration.getContextReceivers();
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, type.getAnnotations(), EnumSet.of(RECEIVER)); List<ReceiverParameterDescriptor> contextReceiverDescriptors =
return DescriptorFactory.createExtensionReceiverParameterForCallable( createReceiverDescriptorsForProperty(propertyDescriptor, scopeForDeclarationResolutionWithTypeParameters, trace,
propertyDescriptor, type, splitter.getAnnotationsForTarget(RECEIVER) contextReceivers, receiverToLabelMap);
);
}).collect(Collectors.toList());
LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeForInitializerResolutionWithTypeParameters, propertyDescriptor); LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeForInitializerResolutionWithTypeParameters, propertyDescriptor);
KotlinType propertyType = propertyInfo.getVariableType(); KotlinType propertyType = propertyInfo.getVariableType();
@@ -1037,11 +1022,41 @@ public class DescriptorResolver {
new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(FIELD), propertyDescriptor), new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(FIELD), propertyDescriptor),
new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(PROPERTY_DELEGATE_FIELD), propertyDescriptor) new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(PROPERTY_DELEGATE_FIELD), propertyDescriptor)
); );
trace.record(DESCRIPTOR_TO_NAMED_RECEIVERS, propertyDescriptor, receiverToLabelMap);
trace.record(BindingContext.VARIABLE, variableDeclaration, propertyDescriptor); trace.record(BindingContext.VARIABLE, variableDeclaration, propertyDescriptor);
return propertyDescriptor; return propertyDescriptor;
} }
private List<ReceiverParameterDescriptor> createReceiverDescriptorsForProperty(
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull LexicalScope scopeForResolution,
@NotNull BindingTrace trace,
@NotNull List<KtContextReceiver> contextReceivers,
@NotNull Map<ReceiverParameterDescriptor, String> receiverToLabelMap
) {
Map<KtContextReceiver, KotlinType> contextReceiversToTypes = new LinkedHashMap<>();
for (KtContextReceiver contextReceiver: contextReceivers) {
KtTypeReference typeReference = contextReceiver.typeReference();
if (typeReference == null) {
continue;
}
KotlinType kotlinType = typeResolver.resolveType(scopeForResolution, typeReference, trace, true);
contextReceiversToTypes.put(contextReceiver, kotlinType);
}
return Lists.reverse(contextReceivers).stream().map(contextReceiver -> {
KotlinType receiverType = contextReceiversToTypes.get(contextReceiver);
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, receiverType.getAnnotations(), EnumSet.of(RECEIVER));
ReceiverParameterDescriptor receiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER),
true);
String contextReceiverName = contextReceiver.name();
if (contextReceiverName != null) {
receiverToLabelMap.put(receiverDescriptor, contextReceiverName);
}
return receiverDescriptor;
}).collect(Collectors.toList());
}
@NotNull @NotNull
/*package*/ static KotlinType transformAnonymousTypeIfNeeded( /*package*/ static KotlinType transformAnonymousTypeIfNeeded(
@NotNull DeclarationDescriptorWithVisibility descriptor, @NotNull DeclarationDescriptorWithVisibility descriptor,
@@ -197,7 +197,8 @@ class FunctionDescriptorResolver(
if (function is KtFunctionLiteral) expectedFunctionType.getReceiverType() else null if (function is KtFunctionLiteral) expectedFunctionType.getReceiverType() else null
} }
val contextReceiverTypes = function.contextReceiverTypeReferences.map { val contextReceivers = function.contextReceivers
val contextReceiverTypes = contextReceivers.mapNotNull { it.typeReference() }.map {
typeResolver.resolveType(headerScope, it, trace, true) typeResolver.resolveType(headerScope, it, trace, true)
} }
@@ -225,23 +226,35 @@ class FunctionDescriptorResolver(
} }
} }
val receiverToLabelMap = linkedMapOf<ReceiverParameterDescriptor, String>()
val extensionReceiver = receiverType?.let { val extensionReceiver = receiverType?.let {
val splitter = AnnotationSplitter(storageManager, receiverType.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER)) val splitter = AnnotationSplitter(storageManager, receiverType.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER))
DescriptorFactory.createExtensionReceiverParameterForCallable( DescriptorFactory.createExtensionReceiverParameterForCallable(
functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER) functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER), false
)
}
val contextReceivers = contextReceiverTypes.map {
val splitter = AnnotationSplitter(storageManager, it.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER))
DescriptorFactory.createExtensionReceiverParameterForCallable(
functionDescriptor, it, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER)
) )
}?.apply {
val extensionReceiverName = receiverTypeRef?.nameForReceiverLabel()
if (extensionReceiverName != null) {
receiverToLabelMap[this] = extensionReceiverName
}
} }
val contextReceiverDescriptors = contextReceiverTypes.mapNotNull { type ->
val splitter = AnnotationSplitter(storageManager, type.annotations, EnumSet.of(AnnotationUseSiteTarget.RECEIVER))
DescriptorFactory.createExtensionReceiverParameterForCallable(
functionDescriptor, type, splitter.getAnnotationsForTarget(AnnotationUseSiteTarget.RECEIVER), true
)
}
contextReceiverDescriptors.reversed().zip(contextReceivers.lastIndex downTo 0).forEach { (contextReceiverDescriptor, i) ->
contextReceivers[i].name()?.let {
receiverToLabelMap[contextReceiverDescriptor] = it
}
}
trace.record(BindingContext.DESCRIPTOR_TO_NAMED_RECEIVERS, functionDescriptor, receiverToLabelMap)
functionDescriptor.initialize( functionDescriptor.initialize(
extensionReceiver, extensionReceiver,
getDispatchReceiverParameterIfNeeded(container), getDispatchReceiverParameterIfNeeded(container),
contextReceivers, contextReceiverDescriptors,
typeParameterDescriptors, typeParameterDescriptors,
valueParameterDescriptors, valueParameterDescriptors,
returnType, returnType,
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve; package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Lists;
import kotlin.Unit; import kotlin.Unit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
@@ -73,7 +74,9 @@ public class FunctionDescriptorUtil {
} }
List<ReceiverParameterDescriptor> contextReceiverParameters = descriptor.getContextReceiverParameters(); List<ReceiverParameterDescriptor> contextReceiverParameters = descriptor.getContextReceiverParameters();
if (!contextReceiverParameters.isEmpty()) { if (!contextReceiverParameters.isEmpty()) {
implicitReceivers.addAll(contextReceiverParameters); implicitReceivers.addAll(
Lists.reverse(contextReceiverParameters)
);
} }
return new LexicalScopeImpl( return new LexicalScopeImpl(
outerScope, descriptor, true, implicitReceivers, outerScope, descriptor, true, implicitReceivers,
@@ -180,7 +180,7 @@ internal fun getIdForStableIdentifier(
is KtThisExpression -> { is KtThisExpression -> {
val declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.instanceReference) val declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.instanceReference)
getIdForThisReceiver(declarationDescriptor) getIdForThisReceiver(declarationDescriptor, bindingContext, expression.getLabelName())
} }
is KtPostfixExpression -> { is KtPostfixExpression -> {
@@ -229,7 +229,7 @@ private fun getIdForSimpleNameExpression(
if (implicitReceiver == null) { if (implicitReceiver == null) {
selectorInfo selectorInfo
} else { } else {
val receiverInfo = getIdForImplicitReceiver(implicitReceiver, simpleNameExpression) val receiverInfo = getIdForImplicitReceiver(implicitReceiver, simpleNameExpression, bindingContext)
if (receiverInfo == null) { if (receiverInfo == null) {
selectorInfo selectorInfo
@@ -255,9 +255,9 @@ private fun getIdForSimpleNameExpression(
} }
} }
private fun getIdForImplicitReceiver(receiverValue: ReceiverValue?, expression: KtExpression?) = private fun getIdForImplicitReceiver(receiverValue: ReceiverValue?, expression: KtExpression?, bindingContext: BindingContext) =
when (receiverValue) { when (receiverValue) {
is ImplicitReceiver -> getIdForThisReceiver(receiverValue.declarationDescriptor) is ImplicitReceiver -> getIdForThisReceiver(receiverValue.declarationDescriptor, bindingContext)
is TransientReceiver -> is TransientReceiver ->
throw AssertionError("Transient receiver is implicit for an explicit expression: $expression. Receiver: $receiverValue") throw AssertionError("Transient receiver is implicit for an explicit expression: $expression. Receiver: $receiverValue")
@@ -265,16 +265,48 @@ private fun getIdForImplicitReceiver(receiverValue: ReceiverValue?, expression:
else -> null else -> null
} }
private fun getIdForThisReceiver(descriptorOfThisReceiver: DeclarationDescriptor?) = when (descriptorOfThisReceiver) { private fun getIdForThisReceiver(
is CallableDescriptor -> { descriptorOfThisReceiver: DeclarationDescriptor?,
val receiverParameter = descriptorOfThisReceiver.extensionReceiverParameter bindingContext: BindingContext,
?: error("'This' refers to the callable member without a receiver parameter: $descriptorOfThisReceiver") labelName: String? = null
IdentifierInfo.Receiver(receiverParameter.value) ) =
when (descriptorOfThisReceiver) {
is CallableDescriptor -> {
val receiverParameter = findReceiverByLabelOrGetDefault(
descriptorOfThisReceiver,
descriptorOfThisReceiver.extensionReceiverParameter,
bindingContext,
labelName
)
IdentifierInfo.Receiver(receiverParameter.value)
}
is ClassDescriptor -> {
val receiverParameter = findReceiverByLabelOrGetDefault(
descriptorOfThisReceiver,
descriptorOfThisReceiver.thisAsReceiverParameter,
bindingContext,
labelName
)
IdentifierInfo.Receiver(receiverParameter.value)
}
else -> IdentifierInfo.NO
} }
is ClassDescriptor -> IdentifierInfo.Receiver(descriptorOfThisReceiver.thisAsReceiverParameter.value) private fun findReceiverByLabelOrGetDefault(
descriptorOfThisReceiver: DeclarationDescriptor,
else -> IdentifierInfo.NO default: ReceiverParameterDescriptor?,
bindingContext: BindingContext,
labelName: String? = null
): ReceiverParameterDescriptor {
val receiverToLabelMap = bindingContext.get(
BindingContext.DESCRIPTOR_TO_NAMED_RECEIVERS,
if (descriptorOfThisReceiver is PropertyAccessorDescriptor) descriptorOfThisReceiver.correspondingProperty else descriptorOfThisReceiver
)
return receiverToLabelMap?.entries?.find {
it.value == labelName
}?.key ?: default ?: error("'This' refers to the callable member without a receiver parameter: $descriptorOfThisReceiver")
} }
private fun postfix(argumentInfo: IdentifierInfo, op: KtToken): IdentifierInfo = private fun postfix(argumentInfo: IdentifierInfo, op: KtToken): IdentifierInfo =
@@ -49,10 +49,7 @@ import org.jetbrains.kotlin.storage.StorageManager;
import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner; import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static kotlin.collections.CollectionsKt.firstOrNull; import static kotlin.collections.CollectionsKt.firstOrNull;
@@ -308,13 +305,17 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
if (classOrObject == null) { if (classOrObject == null) {
return CollectionsKt.emptyList(); return CollectionsKt.emptyList();
} }
return classOrObject.getContextReceiverTypeReferences().stream().map(typeReference -> { return classOrObject.getContextReceivers().stream()
KotlinType kotlinType = c.getTypeResolver().resolveType(getScopeForClassHeaderResolution(), typeReference, c.getTrace(), true); .map(KtContextReceiver::typeReference)
return new ReceiverParameterDescriptorImpl( .filter(Objects::nonNull)
this, .map(typeReference -> {
new ExtensionClassReceiver(this, kotlinType, null), KotlinType kotlinType =
Annotations.Companion.getEMPTY() c.getTypeResolver().resolveType(getScopeForClassHeaderResolution(), typeReference, c.getTrace(), true);
); return new ReceiverParameterDescriptorImpl(
this,
new ExtensionClassReceiver(this, kotlinType, null),
Annotations.Companion.getEMPTY()
);
}).collect(Collectors.toList()); }).collect(Collectors.toList());
}); });
} }
@@ -67,6 +67,7 @@ import org.jetbrains.kotlin.resolve.constants.*;
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind; import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope; import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt; import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt;
import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.*;
@@ -596,7 +597,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
} }
else if (!receivers.isEmpty()) { else if (!receivers.isEmpty()) {
result = receivers.get(0); // `this` cannot point to context receiver
for (ReceiverParameterDescriptor receiver : receivers) {
if (!(receiver.getValue() instanceof ExtensionReceiver) || !((ExtensionReceiver) receiver.getValue()).isContextReceiver()) {
result = receiver;
break;
}
}
} }
if (result != null) { if (result != null) {
context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), result.getContainingDeclaration()); context.trace.record(REFERENCE_TARGET, expression.getInstanceReference(), result.getContainingDeclaration());
@@ -17,28 +17,29 @@
package org.jetbrains.kotlin.types.expressions package org.jetbrains.kotlin.types.expressions
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH import org.jetbrains.kotlin.diagnostics.Errors.LABEL_NAME_CLASH
import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE import org.jetbrains.kotlin.diagnostics.Errors.UNRESOLVED_REFERENCE
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.checkReservedYield import org.jetbrains.kotlin.psi.psiUtil.checkReservedYield
import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.BindingContext.LABEL_TARGET import org.jetbrains.kotlin.resolve.BindingContext.*
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.scopes.utils.getDeclarationsByLabel import org.jetbrains.kotlin.resolve.scopes.utils.getDeclarationsByLabel
import org.jetbrains.kotlin.utils.addIfNotNull
object LabelResolver { object LabelResolver {
private fun getElementsByLabelName(labelName: Name, labelExpression: KtSimpleNameExpression): Set<KtElement> { private fun getElementsByLabelName(
labelName: Name,
labelExpression: KtSimpleNameExpression,
isThisExpression: Boolean
): Set<KtElement> {
val elements = linkedSetOf<KtElement>() val elements = linkedSetOf<KtElement>()
var parent: PsiElement? = labelExpression.parent var parent: PsiElement? = labelExpression.parent
while (parent != null) { while (parent != null) {
val name = getLabelNameIfAny(parent) val names = getLabelNamesIfAny(parent, isThisExpression)
if (name != null && name == labelName) { if (names.contains(labelName)) {
elements.add(getExpressionUnderLabel(parent as KtExpression)) elements.add(getExpressionUnderLabel(parent as KtExpression))
} }
parent = if (parent is KtCodeFragment) parent.context else parent.parent parent = if (parent is KtCodeFragment) parent.context else parent.parent
@@ -46,20 +47,33 @@ object LabelResolver {
return elements return elements
} }
fun getLabelNameIfAny(element: PsiElement): Name? { fun getLabelNamesIfAny(element: PsiElement, addContextReceiverNames: Boolean): List<Name> {
return when (element) { val result = mutableListOf<Name>()
is KtLabeledExpression -> element.getLabelNameAsName() when (element) {
is KtFunctionLiteral -> getLabelNameIfAny(element.parent) is KtLabeledExpression -> result.addIfNotNull(element.getLabelNameAsName())
is KtLambdaExpression -> getLabelForFunctionalExpression(element) // TODO: Support context receivers in function literals
is KtNamedFunction -> element.nameAsName ?: getLabelForFunctionalExpression(element) is KtFunctionLiteral -> return getLabelNamesIfAny(element.parent, false)
else -> null is KtLambdaExpression -> result.addIfNotNull(getLabelForFunctionalExpression(element))
} }
val functionOrProperty = when (element) {
is KtNamedFunction -> element
is KtPropertyAccessor -> element.property
else -> return result
}
if (addContextReceiverNames) {
functionOrProperty.contextReceivers
.mapNotNullTo(result) { it.name()?.let { s -> Name.identifier(s) } }
functionOrProperty.receiverTypeReference?.nameForReceiverLabel()?.let { result.add(Name.identifier(it)) }
}
val name = functionOrProperty.nameAsName ?: getLabelForFunctionalExpression(functionOrProperty)
result.addIfNotNull(name)
return result
} }
private fun getLabelForFunctionalExpression(element: KtExpression): Name? { private fun getLabelForFunctionalExpression(element: KtExpression): Name? {
val parent = element.parent val parent = element.parent
return when (parent) { return when (parent) {
is KtLabeledExpression -> getLabelNameIfAny(parent) is KtLabeledExpression -> getLabelNamesIfAny(parent, false).singleOrNull()
is KtBinaryExpression -> parent.operationReference.getReferencedNameAsName() is KtBinaryExpression -> parent.operationReference.getReferencedNameAsName()
else -> getCallerName(element) else -> getCallerName(element)
} }
@@ -105,7 +119,7 @@ object LabelResolver {
val labelName = expression.getLabelNameAsName() val labelName = expression.getLabelNameAsName()
if (labelElement == null || labelName == null) return null if (labelElement == null || labelName == null) return null
return resolveNamedLabel(labelName, labelElement, context.trace) ?: run { return resolveNamedLabel(labelName, labelElement, context.trace, false) ?: run {
context.trace.report(UNRESOLVED_REFERENCE.on(labelElement, labelElement)) context.trace.report(UNRESOLVED_REFERENCE.on(labelElement, labelElement))
null null
} }
@@ -114,9 +128,10 @@ object LabelResolver {
private fun resolveNamedLabel( private fun resolveNamedLabel(
labelName: Name, labelName: Name,
labelExpression: KtSimpleNameExpression, labelExpression: KtSimpleNameExpression,
trace: BindingTrace trace: BindingTrace,
isThisExpression: Boolean
): KtElement? { ): KtElement? {
val list = getElementsByLabelName(labelName, labelExpression) val list = getElementsByLabelName(labelName, labelExpression, isThisExpression)
if (list.isEmpty()) return null if (list.isEmpty()) return null
if (list.size > 1) { if (list.size > 1) {
@@ -160,10 +175,14 @@ object LabelResolver {
return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver) return LabeledReceiverResolutionResult.labelResolutionSuccess(thisReceiver)
} }
0 -> { 0 -> {
val element = resolveNamedLabel(labelName, targetLabel, context.trace) val element = resolveNamedLabel(labelName, targetLabel, context.trace, expression is KtThisExpression)
val declarationDescriptor = context.trace.bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, element] val declarationDescriptor = context.trace.bindingContext[DECLARATION_TO_DESCRIPTOR, element]
if (declarationDescriptor is FunctionDescriptor) { if (declarationDescriptor is FunctionDescriptor) {
val thisReceiver = declarationDescriptor.extensionReceiverParameter val receiverToLabelMap =
context.trace.bindingContext[DESCRIPTOR_TO_NAMED_RECEIVERS, if (declarationDescriptor is PropertyAccessorDescriptor) declarationDescriptor.correspondingProperty else declarationDescriptor]
val thisReceiver = receiverToLabelMap?.entries?.find {
it.value == labelName.identifier
}?.key ?: declarationDescriptor.extensionReceiverParameter
if (thisReceiver != null) { if (thisReceiver != null) {
context.trace.record(LABEL_TARGET, targetLabel, element) context.trace.record(LABEL_TARGET, targetLabel, element)
context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor) context.trace.record(REFERENCE_TARGET, referenceExpression, declarationDescriptor)
@@ -50,7 +50,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
declareSimpleFunction( declareSimpleFunction(
ktFunction, ktFunction,
ktFunction.receiverTypeReference, ktFunction.receiverTypeReference,
ktFunction.contextReceiverTypeReferences, ktFunction.contextReceivers.mapNotNull { it.typeReference() },
origin, origin,
getOrFail(BindingContext.FUNCTION, ktFunction) getOrFail(BindingContext.FUNCTION, ktFunction)
) { ) {
@@ -127,7 +127,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType() irAccessor.returnType = irAccessor.descriptor.returnType!!.toIrType()
generateValueParameterDeclarations( generateValueParameterDeclarations(
irAccessor, ktAccessor ?: ktProperty, ktProperty.receiverTypeReference, irAccessor, ktAccessor ?: ktProperty, ktProperty.receiverTypeReference,
ktProperty.contextReceiverTypeReferences ktProperty.contextReceivers.mapNotNull { it.typeReference() }
) )
val ktBodyExpression = ktAccessor?.bodyExpression val ktBodyExpression = ktAccessor?.bodyExpression
irAccessor.body = irAccessor.body =
@@ -237,7 +237,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
declareConstructor( declareConstructor(
ktClassOrObject, ktClassOrObject,
ktClassOrObject.primaryConstructor ?: ktClassOrObject, ktClassOrObject.primaryConstructor ?: ktClassOrObject,
ktClassOrObject.contextReceiverTypeReferences, ktClassOrObject.contextReceivers.mapNotNull { it.typeReference() },
primaryConstructorDescriptor primaryConstructorDescriptor
) { irConstructor -> ) { irConstructor ->
if ( if (
@@ -254,7 +254,7 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
return declareConstructor( return declareConstructor(
ktConstructor, ktConstructor,
ktConstructor, ktConstructor,
ktClassOrObject.contextReceiverTypeReferences, ktClassOrObject.contextReceivers.mapNotNull { it.typeReference() },
constructorDescriptor constructorDescriptor
) { ) {
when { when {
@@ -422,12 +422,16 @@ class StatementGenerator(
generateThisReceiver(startOffset, endOffset, referenceTarget.thisAsReceiverParameter.type, referenceTarget) generateThisReceiver(startOffset, endOffset, referenceTarget.thisAsReceiverParameter.type, referenceTarget)
is CallableDescriptor -> { is CallableDescriptor -> {
val extensionReceiver = referenceTarget.extensionReceiverParameter ?: TODO("No extension receiver: $referenceTarget") val resolvedCall = getResolvedCall(expression)
val extensionReceiverType = extensionReceiver.type.toIrType() val receivers = listOfNotNull(referenceTarget.extensionReceiverParameter) + referenceTarget.contextReceiverParameters
val receiver = receivers.find {
it == resolvedCall?.candidateDescriptor
} ?: referenceTarget.extensionReceiverParameter ?: TODO("No receiver: $referenceTarget")
val receiverType = receiver.type.toIrType()
IrGetValueImpl( IrGetValueImpl(
startOffset, endOffset, startOffset, endOffset,
extensionReceiverType, receiverType,
context.symbolTable.referenceValueParameter(extensionReceiver) context.symbolTable.referenceValueParameter(receiver)
) )
} }
@@ -40,6 +40,7 @@ public interface KtNodeTypes {
IElementType SECONDARY_CONSTRUCTOR = KtStubElementTypes.SECONDARY_CONSTRUCTOR; IElementType SECONDARY_CONSTRUCTOR = KtStubElementTypes.SECONDARY_CONSTRUCTOR;
IElementType PRIMARY_CONSTRUCTOR = KtStubElementTypes.PRIMARY_CONSTRUCTOR; IElementType PRIMARY_CONSTRUCTOR = KtStubElementTypes.PRIMARY_CONSTRUCTOR;
IElementType CONTEXT_RECEIVER = KtStubElementTypes.CONTEXT_RECEIVER; IElementType CONTEXT_RECEIVER = KtStubElementTypes.CONTEXT_RECEIVER;
IElementType CONTEXT_RECEIVER_LIST = KtStubElementTypes.CONTEXT_RECEIVER_LIST;
IElementType TYPE_PARAMETER_LIST = KtStubElementTypes.TYPE_PARAMETER_LIST; IElementType TYPE_PARAMETER_LIST = KtStubElementTypes.TYPE_PARAMETER_LIST;
IElementType TYPE_PARAMETER = KtStubElementTypes.TYPE_PARAMETER; IElementType TYPE_PARAMETER = KtStubElementTypes.TYPE_PARAMETER;
@@ -597,7 +597,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
} }
} }
private boolean isAtLabelDefinitionOrMissingIdentifier() { boolean isAtLabelDefinitionOrMissingIdentifier() {
return (at(IDENTIFIER) && myBuilder.rawLookup(1) == AT) || at(AT); return (at(IDENTIFIER) && myBuilder.rawLookup(1) == AT) || at(AT);
} }
@@ -1690,7 +1690,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
/* /*
* IDENTIFIER "@" * IDENTIFIER "@"
*/ */
private void parseLabelDefinition() { void parseLabelDefinition() {
PsiBuilder.Marker labelWrap = mark(); PsiBuilder.Marker labelWrap = mark();
PsiBuilder.Marker mark = mark(); PsiBuilder.Marker mark = mark();
@@ -33,7 +33,7 @@ public interface KtCallableDeclaration extends KtNamedDeclaration, KtTypeParamet
KtTypeReference getReceiverTypeReference(); KtTypeReference getReceiverTypeReference();
@NotNull @NotNull
List<KtTypeReference> getContextReceiverTypeReferences(); List<KtContextReceiver> getContextReceivers();
@Nullable @Nullable
KtTypeReference getTypeReference(); KtTypeReference getTypeReference();
@@ -188,17 +188,17 @@ abstract class KtClassOrObject :
return parts.joinToString(separator = ".") return parts.joinToString(separator = ".")
} }
override fun getContextReceiverTypeReferences(): List<KtTypeReference> { override fun getContextReceivers(): List<KtContextReceiver> {
val stub = stub val stub = stub
if (stub != null) { if (stub != null) {
return getStubOrPsiChildrenAsList(KtStubElementTypes.TYPE_REFERENCE) return getStubOrPsiChildrenAsList(KtStubElementTypes.CONTEXT_RECEIVER)
} }
var node = node.firstChildNode var node = node.firstChildNode
while (node != null) { while (node != null) {
val tt = node.elementType val tt = node.elementType
if (tt === KtNodeTypes.CONTEXT_RECEIVER) { if (tt === KtNodeTypes.CONTEXT_RECEIVER_LIST) {
val contextReceiver = node.psi as KtContextReceiver val contextReceiver = node.psi as KtContextReceiverList
return contextReceiver.typeReferences() return contextReceiver.contextReceivers()
} }
node = node.treeNext node = node.treeNext
} }
@@ -40,7 +40,7 @@ abstract class KtConstructor<T : KtConstructor<T>> : KtDeclarationStub<KotlinPla
override fun getReceiverTypeReference() = null override fun getReceiverTypeReference() = null
override fun getContextReceiverTypeReferences(): List<KtTypeReference> = emptyList() override fun getContextReceivers(): List<KtContextReceiver> = emptyList()
override fun getTypeReference() = null override fun getTypeReference() = null
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.psi
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
@@ -14,9 +15,14 @@ class KtContextReceiver : KtElementImplStub<KotlinPlaceHolderStub<KtContextRecei
constructor(node: ASTNode) : super(node) constructor(node: ASTNode) : super(node)
constructor(stub: KotlinPlaceHolderStub<KtContextReceiver>) : super(stub, KtStubElementTypes.CONTEXT_RECEIVER) constructor(stub: KotlinPlaceHolderStub<KtContextReceiver>) : super(stub, KtStubElementTypes.CONTEXT_RECEIVER)
override fun <R : Any?, D : Any?> accept(visitor: KtVisitor<R, D>, data: D): R { fun targetLabel(): KtSimpleNameExpression? =
return visitor.visitContextReceiver(this, data) findChildByType<KtContainerNode?>(KtNodeTypes.LABEL_QUALIFIER)
} ?.findChildByType(KtNodeTypes.LABEL)
fun typeReferences(): List<KtTypeReference> = findChildrenByType(KtNodeTypes.TYPE_REFERENCE) fun labelName(): String? = targetLabel()?.getReferencedName()
fun labelNameAsName(): Name? = targetLabel()?.getReferencedNameAsName()
fun typeReference(): KtTypeReference? = findChildByType(KtNodeTypes.TYPE_REFERENCE)
fun name(): String? = labelName() ?: typeReference()?.nameForReceiverLabel()
} }
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.psi
import com.intellij.lang.ASTNode
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
class KtContextReceiverList : KtElementImplStub<KotlinPlaceHolderStub<KtContextReceiverList>> {
constructor(node: ASTNode) : super(node)
constructor(stub: KotlinPlaceHolderStub<KtContextReceiverList>) : super(stub, KtStubElementTypes.CONTEXT_RECEIVER_LIST)
override fun <R : Any?, D : Any?> accept(visitor: KtVisitor<R, D>, data: D): R {
return visitor.visitContextReceiverList(this, data)
}
fun contextReceivers(): List<KtContextReceiver> = findChildrenByType(KtNodeTypes.CONTEXT_RECEIVER)
fun typeReferences(): List<KtTypeReference> = contextReceivers().mapNotNull { it.typeReference() }
}
@@ -77,7 +77,7 @@ public class KtDestructuringDeclarationEntry extends KtNamedDeclarationNotStubbe
@NotNull @NotNull
@Override @Override
public List<KtTypeReference> getContextReceiverTypeReferences() { public List<KtContextReceiver> getContextReceivers() {
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -64,7 +64,7 @@ public abstract class KtFunctionNotStubbed extends KtTypeParameterListOwnerNotSt
@NotNull @NotNull
@Override @Override
public List<KtTypeReference> getContextReceiverTypeReferences() { public List<KtContextReceiver> getContextReceivers() {
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -185,12 +185,12 @@ public class KtNamedFunction extends KtTypeParameterListOwnerStub<KotlinFunction
@NotNull @NotNull
@Override @Override
public List<KtTypeReference> getContextReceiverTypeReferences() { public List<KtContextReceiver> getContextReceivers() {
KotlinFunctionStub stub = getStub(); KotlinFunctionStub stub = getStub();
if (stub != null) { if (stub != null) {
List<KtContextReceiver> childContextReceivers = getStubOrPsiChildrenAsList(KtStubElementTypes.CONTEXT_RECEIVER); List<KtContextReceiverList> childContextReceivers = getStubOrPsiChildrenAsList(KtStubElementTypes.CONTEXT_RECEIVER_LIST);
if (!childContextReceivers.isEmpty()) { if (!childContextReceivers.isEmpty()) {
return childContextReceivers.get(0).typeReferences(); return childContextReceivers.get(0).contextReceivers();
} }
else { else {
return Collections.emptyList(); return Collections.emptyList();
@@ -200,13 +200,13 @@ public class KtNamedFunction extends KtTypeParameterListOwnerStub<KotlinFunction
} }
@NotNull @NotNull
private List<KtTypeReference> getContextReceiverTypeRefsByTree() { private List<KtContextReceiver> getContextReceiverTypeRefsByTree() {
PsiElement child = getFirstChild(); PsiElement child = getFirstChild();
while (child != null) { while (child != null) {
IElementType tt = child.getNode().getElementType(); IElementType tt = child.getNode().getElementType();
if (tt == KtTokens.LPAR || tt == KtTokens.COLON) break; if (tt == KtTokens.LPAR || tt == KtTokens.COLON) break;
if (child instanceof KtContextReceiver) { if (child instanceof KtContextReceiverList) {
return ((KtContextReceiver) child).typeReferences(); return ((KtContextReceiverList) child).contextReceivers();
} }
child = child.getNextSibling(); child = child.getNextSibling();
} }
@@ -195,7 +195,7 @@ public class KtParameter extends KtNamedDeclarationStub<KotlinParameterStub> imp
@NotNull @NotNull
@Override @Override
public List<KtTypeReference> getContextReceiverTypeReferences() { public List<KtContextReceiver> getContextReceivers() {
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -116,12 +116,12 @@ public class KtProperty extends KtTypeParameterListOwnerStub<KotlinPropertyStub>
@NotNull @NotNull
@Override @Override
public List<KtTypeReference> getContextReceiverTypeReferences() { public List<KtContextReceiver> getContextReceivers() {
KotlinPropertyStub stub = getStub(); KotlinPropertyStub stub = getStub();
if (stub != null) { if (stub != null) {
KtContextReceiver contextReceiver = getStubOrPsiChild(KtStubElementTypes.CONTEXT_RECEIVER); KtContextReceiverList contextReceiver = getStubOrPsiChild(KtStubElementTypes.CONTEXT_RECEIVER_LIST);
if (contextReceiver != null) { if (contextReceiver != null) {
return contextReceiver.typeReferences(); return contextReceiver.contextReceivers();
} else { } else {
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -130,16 +130,16 @@ public class KtProperty extends KtTypeParameterListOwnerStub<KotlinPropertyStub>
} }
@NotNull @NotNull
private List<KtTypeReference> getContextReceiverTypeRefsByTree() { private List<KtContextReceiver> getContextReceiverTypeRefsByTree() {
ASTNode node = getNode().getFirstChildNode(); ASTNode node = getNode().getFirstChildNode();
while (node != null) { while (node != null) {
IElementType tt = node.getElementType(); IElementType tt = node.getElementType();
if (tt == KtTokens.COLON) { if (tt == KtTokens.COLON) {
break; break;
} }
if (tt == KtNodeTypes.CONTEXT_RECEIVER) { if (tt == KtNodeTypes.CONTEXT_RECEIVER_LIST) {
KtContextReceiver contextReceiver = (KtContextReceiver) node.getPsi(); KtContextReceiverList contextReceiver = (KtContextReceiverList) node.getPsi();
return contextReceiver.typeReferences(); return contextReceiver.contextReceivers();
} }
node = node.getTreeNext(); node = node.getTreeNext();
} }
@@ -60,7 +60,7 @@ public interface KtPureClassOrObject extends KtPureElement, KtDeclarationContain
@NotNull @NotNull
@ReadOnly @ReadOnly
List<KtTypeReference> getContextReceiverTypeReferences(); List<KtContextReceiver> getContextReceivers();
@Nullable @Nullable
KtClassBody getBody(); KtClassBody getBody();
@@ -55,4 +55,6 @@ class KtTypeReference : KtModifierListOwnerStub<KotlinPlaceHolderStub<KtTypeRefe
fun hasParentheses(): Boolean { fun hasParentheses(): Boolean {
return findChildByType<PsiElement>(KtTokens.LPAR) != null && findChildByType<PsiElement>(KtTokens.RPAR) != null return findChildByType<PsiElement>(KtTokens.LPAR) != null && findChildByType<PsiElement>(KtTokens.RPAR) != null
} }
fun nameForReceiverLabel() = (typeElement as? KtUserType)?.referencedName
} }
@@ -158,8 +158,8 @@ public class KtVisitor<R, D> extends PsiElementVisitor {
return visitSuperTypeListEntry(specifier, data); return visitSuperTypeListEntry(specifier, data);
} }
public R visitContextReceiver(@NotNull KtContextReceiver contextReceiver, D data) { public R visitContextReceiverList(@NotNull KtContextReceiverList contextReceiverList, D data) {
return visitKtElement(contextReceiver, data); return visitKtElement(contextReceiverList, data);
} }
public R visitConstructorDelegationCall(@NotNull KtConstructorDelegationCall call, D data) { public R visitConstructorDelegationCall(@NotNull KtConstructorDelegationCall call, D data) {
@@ -145,6 +145,8 @@ public interface KtStubElementTypes {
KtPlaceHolderStubElementType<KtContextReceiver> CONTEXT_RECEIVER = KtPlaceHolderStubElementType<KtContextReceiver> CONTEXT_RECEIVER =
new KtPlaceHolderStubElementType<>("CONTEXT_RECEIVER", KtContextReceiver.class); new KtPlaceHolderStubElementType<>("CONTEXT_RECEIVER", KtContextReceiver.class);
KtPlaceHolderStubElementType<KtContextReceiverList> CONTEXT_RECEIVER_LIST =
new KtPlaceHolderStubElementType<>("CONTEXT_RECEIVER_LIST", KtContextReceiverList.class);
KtConstantExpressionElementType NULL = new KtConstantExpressionElementType("NULL"); KtConstantExpressionElementType NULL = new KtConstantExpressionElementType("NULL");
KtConstantExpressionElementType BOOLEAN_CONSTANT = new KtConstantExpressionElementType("BOOLEAN_CONSTANT"); KtConstantExpressionElementType BOOLEAN_CONSTANT = new KtConstantExpressionElementType("BOOLEAN_CONSTANT");
@@ -0,0 +1,20 @@
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_FIR: JVM_IR
class A<T>(val a: T)
class B(val b: Any?)
context(A<String>, B) fun f() {
this@A.a.length
this@B.b
}
fun box(): String {
with(A("")) {
with(B(null)) {
f()
}
}
return "OK"
}
@@ -0,0 +1,19 @@
interface Context {
fun h() {}
}
open class A {
open fun f() {}
}
class B : A() {
override fun f() {}
context(Context)
inner class C {
fun g() {
super@B.f()
super@Context.<!UNRESOLVED_REFERENCE!>h<!>()
}
}
}
@@ -0,0 +1,19 @@
interface Context {
fun h() {}
}
open class A {
open fun f() {}
}
class B : A() {
override fun f() {}
context(Context)
inner class C {
fun g() {
super@B.f()
<!DEBUG_INFO_MISSING_UNRESOLVED!>super<!><!UNRESOLVED_REFERENCE!>@Context<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>h<!>()
}
}
}
@@ -0,0 +1,32 @@
package
public open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun f(): 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 B : A {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ fun f(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final inner class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun g(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public interface Context {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun h(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,6 @@
class A(val a: String?)
context(A) fun f() {
if (<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!> == null) return
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
}
@@ -0,0 +1,6 @@
class A(val a: String?)
context(A) fun f() {
if (this@A.a == null) return
<!DEBUG_INFO_SMARTCAST!>this@A.a<!>.length
}
@@ -0,0 +1,11 @@
package
public fun f(): kotlin.Unit
public final class A {
public constructor A(/*0*/ a: kotlin.String?)
public final val a: kotlin.String?
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
}
@@ -0,0 +1,22 @@
class A<T>(val a: T)
class B(val b: Any)
class C(val c: Any)
context(labelAInt@A<Int>, A<String>, labelB@B) fun f() {
<!UNRESOLVED_LABEL!>this@labelAInt<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>toFloat<!>()
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
<!UNRESOLVED_LABEL!>this@labelB<!>.<!UNRESOLVED_REFERENCE!>b<!>
<!UNRESOLVED_LABEL!>this@B<!>
}
context(labelAInt@A<Int>, A<String>, labelB@B) val C.p: Int
get() {
<!UNRESOLVED_LABEL!>this@labelAInt<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>toFloat<!>()
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
<!UNRESOLVED_LABEL!>this@B<!>
<!UNRESOLVED_LABEL!>this@labelB<!>.<!UNRESOLVED_REFERENCE!>b<!>
<!UNRESOLVED_LABEL!>this@C<!>.<!UNRESOLVED_REFERENCE!>c<!>
this@p.c
this.c
return 1
}
@@ -0,0 +1,22 @@
class A<T>(val a: T)
class B(val b: Any)
class C(val c: Any)
context(labelAInt@A<Int>, A<String>, labelB@B) fun f() {
this@labelAInt.a.toFloat()
this@A.a.length
this@labelB.b
this<!UNRESOLVED_REFERENCE!>@B<!>
}
context(labelAInt@A<Int>, A<String>, labelB@B) val C.p: Int
get() {
this@labelAInt.a.toFloat()
this@A.a.length
this<!UNRESOLVED_REFERENCE!>@B<!>
this@labelB.b
this@C.c
this@p.c
this.c
return 1
}
@@ -0,0 +1,28 @@
package
public val C.p: kotlin.Int
public fun f(): kotlin.Unit
public final class A</*0*/ T> {
public constructor A</*0*/ T>(/*0*/ a: T)
public final val a: T
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
}
public final class B {
public constructor B(/*0*/ b: kotlin.Any)
public final val b: kotlin.Any
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
}
public final class C {
public constructor C(/*0*/ c: kotlin.Any)
public final val c: kotlin.Any
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
}
@@ -0,0 +1,9 @@
class A {
val x = 1
}
context(A) class B {
val prop = <!UNRESOLVED_REFERENCE!>x<!> + <!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>x<!>
fun f() = <!UNRESOLVED_REFERENCE!>x<!> + <!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>x<!>
}
@@ -0,0 +1,9 @@
class A {
val x = 1
}
context(A) class B {
val prop = x + this<!UNRESOLVED_REFERENCE!>@A<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>x<!>
fun f() = x + this<!UNRESOLVED_REFERENCE!>@A<!>.<!DEBUG_INFO_MISSING_UNRESOLVED!>x<!>
}
@@ -0,0 +1,18 @@
package
public final class A {
public constructor A()
public final val x: kotlin.Int = 1
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
}
public final class B {
public constructor B()
public final val prop: [ERROR : Type for x + this@A.x]
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun f(): [ERROR : Error function type]
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,17 @@
class A<T>(val a: T)
class B(val b: Any)
class C(val c: Any)
context(A<Int>, A<String>, B) fun f() {
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
<!UNRESOLVED_LABEL!>this@B<!>.<!UNRESOLVED_REFERENCE!>b<!>
<!NO_THIS!>this<!>
}
context(A<Int>, A<String>, B) fun C.f() {
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
<!UNRESOLVED_LABEL!>this@B<!>.<!UNRESOLVED_REFERENCE!>b<!>
<!UNRESOLVED_LABEL!>this@C<!>.<!UNRESOLVED_REFERENCE!>c<!>
this@f.c
this.c
}
@@ -0,0 +1,17 @@
class A<T>(val a: T)
class B(val b: Any)
class C(val c: Any)
context(A<Int>, A<String>, B) fun f() {
this@A.a.length
this@B.b
<!NO_THIS!>this<!>
}
context(A<Int>, A<String>, B) fun C.f() {
this@A.a.length
this@B.b
this@C.c
this@f.c
this.c
}
@@ -0,0 +1,28 @@
package
public fun f(): kotlin.Unit
public fun C.f(): kotlin.Unit
public final class A</*0*/ T> {
public constructor A</*0*/ T>(/*0*/ a: T)
public final val a: T
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
}
public final class B {
public constructor B(/*0*/ b: kotlin.Any)
public final val b: kotlin.Any
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
}
public final class C {
public constructor C(/*0*/ c: kotlin.Any)
public final val c: kotlin.Any
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
}
@@ -0,0 +1,28 @@
class A<T>(val a: T)
class B(val b: Any)
class C(val c: Any)
context(A<Int>, A<String>, B) var p: Int
get() {
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>toDouble<!>()
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
<!UNRESOLVED_LABEL!>this@B<!>.<!UNRESOLVED_REFERENCE!>b<!>
<!NO_THIS!>this<!>
return 1
}
set(value) {
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
<!UNRESOLVED_LABEL!>this@B<!>.<!UNRESOLVED_REFERENCE!>b<!>
<!NO_THIS!>this<!>
field = value
}
context(A<Int>, A<String>, B) val C.p: Int
get() {
<!UNRESOLVED_LABEL!>this@A<!>.<!UNRESOLVED_REFERENCE!>a<!>.<!UNRESOLVED_REFERENCE!>length<!>
<!UNRESOLVED_LABEL!>this@B<!>.<!UNRESOLVED_REFERENCE!>b<!>
<!UNRESOLVED_LABEL!>this@C<!>.<!UNRESOLVED_REFERENCE!>c<!>
this@p.c
this.c
return 1
}
@@ -0,0 +1,28 @@
class A<T>(val a: T)
class B(val b: Any)
class C(val c: Any)
context(A<Int>, A<String>, B) var p: Int
get() {
this@A.a.<!UNRESOLVED_REFERENCE!>toDouble<!>()
this@A.a.length
this@B.b
<!NO_THIS!>this<!>
return 1
}
set(value) {
this@A.a.length
this@B.b
<!NO_THIS!>this<!>
<!UNRESOLVED_REFERENCE!>field<!> = value
}
context(A<Int>, A<String>, B) val C.p: Int
get() {
this@A.a.length
this@B.b
this@C.c
this@p.c
this.c
return 1
}
@@ -0,0 +1,28 @@
package
public var p: kotlin.Int
public val C.p: kotlin.Int
public final class A</*0*/ T> {
public constructor A</*0*/ T>(/*0*/ a: T)
public final val a: T
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
}
public final class B {
public constructor B(/*0*/ b: kotlin.Any)
public final val b: kotlin.Any
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
}
public final class C {
public constructor C(/*0*/ c: kotlin.Any)
public final val c: kotlin.Any
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
}
@@ -10630,6 +10630,42 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/plusMatrix.kt"); runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/plusMatrix.kt");
} }
@Test
@TestMetadata("superWithContext.kt")
public void testSuperWithContext() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/superWithContext.kt");
}
@Test
@TestMetadata("thisIdentifierInfo.kt")
public void testThisIdentifierInfo() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisIdentifierInfo.kt");
}
@Test
@TestMetadata("thisWithCustomLabel.kt")
public void testThisWithCustomLabel() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithCustomLabel.kt");
}
@Test
@TestMetadata("thisWithReceiverLabelsClasses.kt")
public void testThisWithReceiverLabelsClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsClasses.kt");
}
@Test
@TestMetadata("thisWithReceiverLabelsFunctions.kt")
public void testThisWithReceiverLabelsFunctions() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsFunctions.kt");
}
@Test
@TestMetadata("thisWithReceiverLabelsProperties.kt")
public void testThisWithReceiverLabelsProperties() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/thisWithReceiverLabelsProperties.kt");
}
@Test @Test
@TestMetadata("typeParameterized.kt") @TestMetadata("typeParameterized.kt")
public void testTypeParameterized() throws Exception { public void testTypeParameterized() throws Exception {
@@ -16168,6 +16168,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testSimpleCall() throws Exception { public void testSimpleCall() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt"); runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/simpleCall.kt");
} }
@Test
@TestMetadata("this.kt")
public void testThis() throws Exception {
runTest("compiler/testData/codegen/box/extensionFunctions/contextReceivers/this.kt");
}
} }
} }
@@ -188,9 +188,19 @@ public class DescriptorFactory {
@NotNull CallableDescriptor owner, @NotNull CallableDescriptor owner,
@Nullable KotlinType receiverParameterType, @Nullable KotlinType receiverParameterType,
@NotNull Annotations annotations @NotNull Annotations annotations
) {
return createExtensionReceiverParameterForCallable(owner, receiverParameterType, annotations, false);
}
@Nullable
public static ReceiverParameterDescriptor createExtensionReceiverParameterForCallable(
@NotNull CallableDescriptor owner,
@Nullable KotlinType receiverParameterType,
@NotNull Annotations annotations,
boolean isContextReceiver
) { ) {
return receiverParameterType == null return receiverParameterType == null
? null ? null
: new ReceiverParameterDescriptorImpl(owner, new ExtensionReceiver(owner, receiverParameterType, null), annotations); : new ReceiverParameterDescriptorImpl(owner, new ExtensionReceiver(owner, receiverParameterType, null, isContextReceiver), annotations);
} }
} }
@@ -35,14 +35,25 @@ import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker;
public class ExtensionReceiver extends AbstractReceiverValue implements ImplicitReceiver { public class ExtensionReceiver extends AbstractReceiverValue implements ImplicitReceiver {
private final CallableDescriptor descriptor; private final CallableDescriptor descriptor;
private final boolean isContextReceiver;
public ExtensionReceiver( public ExtensionReceiver(
@NotNull CallableDescriptor callableDescriptor, @NotNull CallableDescriptor callableDescriptor,
@NotNull KotlinType receiverType, @NotNull KotlinType receiverType,
@Nullable ReceiverValue original @Nullable ReceiverValue original
) {
this(callableDescriptor, receiverType, original, false);
}
public ExtensionReceiver(
@NotNull CallableDescriptor callableDescriptor,
@NotNull KotlinType receiverType,
@Nullable ReceiverValue original,
boolean isContextReceiver
) { ) {
super(receiverType, original); super(receiverType, original);
this.descriptor = callableDescriptor; this.descriptor = callableDescriptor;
this.isContextReceiver = isContextReceiver;
} }
@NotNull @NotNull
@@ -61,4 +72,8 @@ public class ExtensionReceiver extends AbstractReceiverValue implements Implicit
public String toString() { public String toString() {
return getType() + ": Ext {" + descriptor + "}"; return getType() + ": Ext {" + descriptor + "}";
} }
public boolean isContextReceiver() {
return isContextReceiver;
}
} }