Extract '::' type-checking code to DoubleColonExpressionResolver
This commit is contained in:
+2
-229
@@ -21,7 +21,6 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -29,24 +28,19 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.KtNodeTypes;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.diagnostics.Severity;
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.*;
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.callableReferences.CallableReferencesResolutionUtilsKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver;
|
||||
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl;
|
||||
@@ -61,7 +55,6 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
|
||||
import org.jetbrains.kotlin.resolve.constants.*;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
|
||||
@@ -78,7 +71,6 @@ import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.*;
|
||||
@@ -595,197 +587,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
@Override
|
||||
public KotlinTypeInfo visitClassLiteralExpression(@NotNull KtClassLiteralExpression expression, ExpressionTypingContext c) {
|
||||
KotlinType type = resolveClassLiteral(expression, c);
|
||||
if (type != null && !type.isError()) {
|
||||
return components.dataFlowAnalyzer.createCheckedTypeInfo(
|
||||
components.reflectionTypes.getKClassType(Annotations.Companion.getEMPTY(), type), c, expression
|
||||
);
|
||||
}
|
||||
|
||||
return TypeInfoFactoryKt.createTypeInfo(ErrorUtils.createErrorType("Unresolved class"), c);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KotlinType resolveClassLiteral(@NotNull KtClassLiteralExpression expression, ExpressionTypingContext c) {
|
||||
KtTypeReference typeReference = expression.getTypeReference();
|
||||
|
||||
if (typeReference == null) {
|
||||
// "::class" will mean "this::class", a class of "this" instance
|
||||
c.trace.report(UNSUPPORTED.on(expression, "Class literals with empty left hand side are not yet supported"));
|
||||
return null;
|
||||
}
|
||||
|
||||
TypeResolutionContext context =
|
||||
new TypeResolutionContext(c.scope, c.trace, /* checkBounds = */ false, /* allowBareTypes = */ true, /* isDebuggerContext */ false);
|
||||
PossiblyBareType possiblyBareType =
|
||||
components.typeResolver.resolvePossiblyBareType(context, typeReference);
|
||||
|
||||
KotlinType type = null;
|
||||
if (possiblyBareType.isBare()) {
|
||||
if (!possiblyBareType.isNullable()) {
|
||||
ClassifierDescriptor descriptor = possiblyBareType.getBareTypeConstructor().getDeclarationDescriptor();
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
|
||||
if (KotlinBuiltIns.isNonPrimitiveArray(classDescriptor)) {
|
||||
context.trace.report(ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT.on(expression));
|
||||
return null;
|
||||
}
|
||||
type = substituteWithStarProjections(classDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
KotlinType actualType = possiblyBareType.getActualType();
|
||||
if (actualType.isError()) return null;
|
||||
if (isAllowedInClassLiteral(actualType)) {
|
||||
type = actualType;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
|
||||
context.trace.report(CLASS_LITERAL_LHS_NOT_A_CLASS.on(expression));
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static KotlinType substituteWithStarProjections(@NotNull ClassDescriptor descriptor) {
|
||||
TypeConstructor typeConstructor = descriptor.getTypeConstructor();
|
||||
List<TypeProjection> arguments =
|
||||
CollectionsKt.map(typeConstructor.getParameters(), new Function1<TypeParameterDescriptor, TypeProjection>() {
|
||||
@Override
|
||||
public TypeProjection invoke(TypeParameterDescriptor descriptor) {
|
||||
return TypeUtils.makeStarProjection(descriptor);
|
||||
}
|
||||
});
|
||||
|
||||
return KotlinTypeImpl.create(Annotations.Companion.getEMPTY(), descriptor, false, arguments);
|
||||
}
|
||||
|
||||
private static boolean isAllowedInClassLiteral(@NotNull KotlinType type) {
|
||||
return isClassAvailableAtRuntime(type, false);
|
||||
}
|
||||
|
||||
private static boolean isClassAvailableAtRuntime(@NotNull KotlinType type, boolean canBeNullable) {
|
||||
if (type.isMarkedNullable() && !canBeNullable) return false;
|
||||
|
||||
TypeConstructor typeConstructor = type.getConstructor();
|
||||
ClassifierDescriptor typeDeclarationDescriptor = typeConstructor.getDeclarationDescriptor();
|
||||
boolean typeIsArray = KotlinBuiltIns.isArray(type);
|
||||
|
||||
if (typeDeclarationDescriptor instanceof ClassDescriptor) {
|
||||
List<TypeParameterDescriptor> parameters = typeConstructor.getParameters();
|
||||
if (parameters.size() != type.getArguments().size()) return false;
|
||||
|
||||
Iterator<TypeProjection> typeArgumentsIterator = type.getArguments().iterator();
|
||||
for (TypeParameterDescriptor parameter : parameters) {
|
||||
if (!typeIsArray && !parameter.isReified()) return false;
|
||||
|
||||
TypeProjection typeArgument = typeArgumentsIterator.next();
|
||||
|
||||
if (typeArgument == null) return false;
|
||||
if (typeArgument.isStarProjection()) return false;
|
||||
if (!isClassAvailableAtRuntime(typeArgument.getType(), true)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (typeDeclarationDescriptor instanceof TypeParameterDescriptor) {
|
||||
return ((TypeParameterDescriptor) typeDeclarationDescriptor).isReified();
|
||||
}
|
||||
|
||||
return false;
|
||||
return components.doubleColonExpressionResolver.visitClassLiteralExpression(expression, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KotlinTypeInfo visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, ExpressionTypingContext c) {
|
||||
KtTypeReference typeReference = expression.getTypeReference();
|
||||
|
||||
KotlinType receiverType =
|
||||
typeReference == null
|
||||
? null
|
||||
: components.typeResolver.resolveType(c.scope, typeReference, c.trace, false);
|
||||
|
||||
KtSimpleNameExpression callableReference = expression.getCallableReference();
|
||||
if (callableReference.getReferencedName().isEmpty()) {
|
||||
c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference));
|
||||
KotlinType errorType = ErrorUtils.createErrorType("Empty callable reference");
|
||||
return components.dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression);
|
||||
}
|
||||
|
||||
TemporaryBindingTrace trace = TemporaryBindingTrace.create(c.trace, "Callable reference type");
|
||||
KotlinType result = getCallableReferenceType(expression, receiverType, c.replaceBindingTrace(trace));
|
||||
boolean hasErrors = hasErrors(trace); // Do not inline this local variable (execution order is important)
|
||||
trace.commit();
|
||||
if (!hasErrors && result != null) {
|
||||
checkNoExpressionOnLHS(expression, c);
|
||||
}
|
||||
return components.dataFlowAnalyzer.createCheckedTypeInfo(result, c, expression);
|
||||
}
|
||||
|
||||
private static boolean hasErrors(TemporaryBindingTrace trace) {
|
||||
for (Diagnostic diagnostic : trace.getBindingContext().getDiagnostics().all()) {
|
||||
if (diagnostic.getSeverity() == Severity.ERROR) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkNoExpressionOnLHS(@NotNull KtCallableReferenceExpression expression, @NotNull ExpressionTypingContext c) {
|
||||
KtTypeReference typeReference = expression.getTypeReference();
|
||||
if (typeReference == null) return;
|
||||
KtTypeElement typeElement = typeReference.getTypeElement();
|
||||
if (!(typeElement instanceof KtUserType)) return;
|
||||
|
||||
KtUserType userType = (KtUserType) typeElement;
|
||||
while (true) {
|
||||
if (userType.getTypeArgumentList() != null) return;
|
||||
KtUserType qualifier = userType.getQualifier();
|
||||
if (qualifier == null) break;
|
||||
userType = qualifier;
|
||||
}
|
||||
|
||||
KtSimpleNameExpression simpleNameExpression = userType.getReferenceExpression();
|
||||
if (simpleNameExpression == null) return;
|
||||
|
||||
TemporaryTraceAndCache traceAndCache =
|
||||
TemporaryTraceAndCache.create(c, "Resolve expression on LHS of callable reference", simpleNameExpression);
|
||||
OverloadResolutionResults<VariableDescriptor> resolutionResult =
|
||||
components.callExpressionResolver.resolveSimpleName(c.replaceTraceAndCache(traceAndCache), simpleNameExpression);
|
||||
|
||||
Collection<? extends ResolvedCall<VariableDescriptor>> resultingCalls =
|
||||
CollectionsKt.filter(resolutionResult.getResultingCalls(), new Function1<ResolvedCall<VariableDescriptor>, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(ResolvedCall<VariableDescriptor> call) {
|
||||
return call.getStatus().possibleTransformToSuccess();
|
||||
}
|
||||
});
|
||||
|
||||
if (resultingCalls.isEmpty()) return;
|
||||
|
||||
if (resultingCalls.size() == 1 &&
|
||||
resultingCalls.iterator().next().getResultingDescriptor() instanceof FakeCallableDescriptorForObject) return;
|
||||
|
||||
ResolvedCall<?> originalResolvedCall = CallUtilKt.getResolvedCall(expression.getCallableReference(), c.trace.getBindingContext());
|
||||
CallableDescriptor originalResult = originalResolvedCall == null ? null : originalResolvedCall.getResultingDescriptor();
|
||||
|
||||
throw new AssertionError(String.format(
|
||||
"Expressions on left-hand side of callable reference are not supported yet.\n" +
|
||||
"Resolution result: %s\n" +
|
||||
"Original result: %s",
|
||||
CollectionsKt.map(
|
||||
resultingCalls, new Function1<ResolvedCall<VariableDescriptor>, VariableDescriptor>() {
|
||||
@Override
|
||||
public VariableDescriptor invoke(ResolvedCall<VariableDescriptor> call) {
|
||||
return call.getResultingDescriptor();
|
||||
}
|
||||
}
|
||||
),
|
||||
originalResult
|
||||
));
|
||||
return components.doubleColonExpressionResolver.visitCallableReferenceExpression(expression, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -847,40 +654,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return resultTypeInfo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private KotlinType getCallableReferenceType(
|
||||
@NotNull KtCallableReferenceExpression expression,
|
||||
@Nullable KotlinType lhsType,
|
||||
@NotNull ExpressionTypingContext context
|
||||
) {
|
||||
KtSimpleNameExpression reference = expression.getCallableReference();
|
||||
|
||||
boolean[] resolved = new boolean[1];
|
||||
CallableDescriptor descriptor = CallableReferencesResolutionUtilsKt.resolveCallableReferenceTarget(
|
||||
expression, lhsType, context, resolved, components.callResolver);
|
||||
if (!resolved[0]) {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference));
|
||||
}
|
||||
if (descriptor == null) return null;
|
||||
|
||||
if (expression.getTypeReference() == null &&
|
||||
(descriptor.getDispatchReceiverParameter() != null || descriptor.getExtensionReceiverParameter() != null)) {
|
||||
context.trace.report(CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS.on(reference));
|
||||
}
|
||||
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (DescriptorUtils.isObject(containingDeclaration)) {
|
||||
context.trace.report(CALLABLE_REFERENCE_TO_OBJECT_MEMBER.on(reference));
|
||||
}
|
||||
if (descriptor instanceof ConstructorDescriptor && DescriptorUtils.isAnnotationClass(containingDeclaration)) {
|
||||
context.trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(reference));
|
||||
}
|
||||
|
||||
return CallableReferencesResolutionUtilsKt.createReflectionTypeForResolvedCallableReference(
|
||||
expression, lhsType, descriptor, context, components.reflectionTypes
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KotlinTypeInfo visitQualifiedExpression(@NotNull KtQualifiedExpression expression, ExpressionTypingContext context) {
|
||||
CallExpressionResolver callExpressionResolver = components.callExpressionResolver;
|
||||
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.types.expressions
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.psi.KtUserType
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.TypeResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.TypeResolver
|
||||
import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForResolvedCallableReference
|
||||
import org.jetbrains.kotlin.resolve.callableReferences.resolveCallableReferenceTarget
|
||||
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeImpl
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
||||
|
||||
class DoubleColonExpressionResolver(
|
||||
val callResolver: CallResolver,
|
||||
val callExpressionResolver: CallExpressionResolver,
|
||||
val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
val reflectionTypes: ReflectionTypes,
|
||||
val typeResolver: TypeResolver
|
||||
) {
|
||||
fun visitClassLiteralExpression(expression: KtClassLiteralExpression, c: ExpressionTypingContext): KotlinTypeInfo {
|
||||
val type = resolveClassLiteral(expression, c)
|
||||
if (type != null && !type.isError) {
|
||||
return dataFlowAnalyzer.createCheckedTypeInfo(reflectionTypes.getKClassType(Annotations.EMPTY, type), c, expression)
|
||||
}
|
||||
|
||||
return createTypeInfo(ErrorUtils.createErrorType("Unresolved class"), c)
|
||||
}
|
||||
|
||||
private fun resolveClassLiteral(expression: KtClassLiteralExpression, c: ExpressionTypingContext): KotlinType? {
|
||||
val typeReference = expression.typeReference
|
||||
|
||||
if (typeReference == null) {
|
||||
// "::class" will maybe mean "this::class", a class of "this" instance
|
||||
c.trace.report(UNSUPPORTED.on(expression, "Class literals with empty left hand side are not yet supported"))
|
||||
return null
|
||||
}
|
||||
|
||||
val context = TypeResolutionContext(
|
||||
c.scope, c.trace, /* checkBounds = */ false, /* allowBareTypes = */ true, /* isDebuggerContext = */ false
|
||||
)
|
||||
val possiblyBareType = typeResolver.resolvePossiblyBareType(context, typeReference)
|
||||
|
||||
var type: KotlinType? = null
|
||||
if (possiblyBareType.isBare) {
|
||||
if (!possiblyBareType.isNullable) {
|
||||
val descriptor = possiblyBareType.bareTypeConstructor.declarationDescriptor
|
||||
if (descriptor is ClassDescriptor) {
|
||||
if (KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
|
||||
context.trace.report(ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT.on(expression))
|
||||
return null
|
||||
}
|
||||
type = KotlinTypeImpl.create(
|
||||
Annotations.EMPTY, descriptor, false, descriptor.typeConstructor.parameters.map(TypeUtils::makeStarProjection)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
val actualType = possiblyBareType.actualType
|
||||
if (actualType.isError) return null
|
||||
if (isAllowedInClassLiteral(actualType)) {
|
||||
type = actualType
|
||||
}
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
return type
|
||||
}
|
||||
|
||||
context.trace.report(CLASS_LITERAL_LHS_NOT_A_CLASS.on(expression))
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isAllowedInClassLiteral(type: KotlinType): Boolean =
|
||||
isClassifierAvailableAtRuntime(type, false)
|
||||
|
||||
private fun isClassifierAvailableAtRuntime(type: KotlinType, canBeNullable: Boolean): Boolean {
|
||||
if (type.isMarkedNullable && !canBeNullable) return false
|
||||
|
||||
val typeConstructor = type.constructor
|
||||
val typeDeclarationDescriptor = typeConstructor.declarationDescriptor
|
||||
val typeIsArray = KotlinBuiltIns.isArray(type)
|
||||
|
||||
when (typeDeclarationDescriptor) {
|
||||
is ClassDescriptor -> {
|
||||
val parameters = typeConstructor.parameters
|
||||
if (parameters.size != type.arguments.size) return false
|
||||
|
||||
val typeArgumentsIterator = type.arguments.iterator()
|
||||
for (parameter in parameters) {
|
||||
if (!typeIsArray && !parameter.isReified) return false
|
||||
|
||||
val typeArgument = typeArgumentsIterator.next() ?: return false
|
||||
|
||||
if (typeArgument.isStarProjection) return false
|
||||
if (!isClassifierAvailableAtRuntime(typeArgument.type, true)) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
is TypeParameterDescriptor -> return typeDeclarationDescriptor.isReified
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
||||
fun visitCallableReferenceExpression(expression: KtCallableReferenceExpression, c: ExpressionTypingContext): KotlinTypeInfo {
|
||||
val typeReference = expression.typeReference
|
||||
|
||||
val receiverType = typeReference?.let { typeReference ->
|
||||
typeResolver.resolveType(c.scope, typeReference, c.trace, false)
|
||||
}
|
||||
|
||||
val callableReference = expression.callableReference
|
||||
if (callableReference.getReferencedName().isEmpty()) {
|
||||
c.trace.report(UNRESOLVED_REFERENCE.on(callableReference, callableReference))
|
||||
val errorType = ErrorUtils.createErrorType("Empty callable reference")
|
||||
return dataFlowAnalyzer.createCheckedTypeInfo(errorType, c, expression)
|
||||
}
|
||||
|
||||
val trace = TemporaryBindingTrace.create(c.trace, "Callable reference type")
|
||||
val result = getCallableReferenceType(expression, receiverType, c.replaceBindingTrace(trace))
|
||||
val hasErrors = hasErrors(trace) // Do not inline this local variable (execution order is important)
|
||||
trace.commit()
|
||||
if (!hasErrors && result != null) {
|
||||
checkNoExpressionOnLHS(expression, c)
|
||||
}
|
||||
return dataFlowAnalyzer.createCheckedTypeInfo(result, c, expression)
|
||||
}
|
||||
|
||||
private fun hasErrors(trace: TemporaryBindingTrace): Boolean =
|
||||
trace.bindingContext.diagnostics.all().any { diagnostic -> diagnostic.severity == Severity.ERROR }
|
||||
|
||||
private fun checkNoExpressionOnLHS(expression: KtCallableReferenceExpression, c: ExpressionTypingContext) {
|
||||
val typeReference = expression.typeReference ?: return
|
||||
var typeElement = typeReference.typeElement as? KtUserType ?: return
|
||||
|
||||
while (true) {
|
||||
if (typeElement.typeArgumentList != null) return
|
||||
typeElement = typeElement.qualifier ?: break
|
||||
}
|
||||
|
||||
val simpleNameExpression = typeElement.referenceExpression ?: return
|
||||
|
||||
val traceAndCache = TemporaryTraceAndCache.create(c, "Resolve expression on LHS of callable reference", simpleNameExpression)
|
||||
val resolutionResult = callExpressionResolver.resolveSimpleName(c.replaceTraceAndCache(traceAndCache), simpleNameExpression)
|
||||
|
||||
val resultingCalls = resolutionResult.resultingCalls.filter { call -> call.status.possibleTransformToSuccess() }
|
||||
if (resultingCalls.isEmpty()) return
|
||||
|
||||
if (resultingCalls.singleOrNull()?.resultingDescriptor is FakeCallableDescriptorForObject) return
|
||||
|
||||
throw AssertionError(String.format(
|
||||
"Expressions on left-hand side of callable reference are not supported yet.\n" +
|
||||
"Resolution result: %s\n" +
|
||||
"Original result: %s",
|
||||
resultingCalls.map { call -> call.resultingDescriptor },
|
||||
expression.callableReference.getResolvedCall(c.trace.bindingContext)?.resultingDescriptor
|
||||
))
|
||||
}
|
||||
|
||||
private fun getCallableReferenceType(
|
||||
expression: KtCallableReferenceExpression,
|
||||
lhsType: KotlinType?,
|
||||
context: ExpressionTypingContext
|
||||
): KotlinType? {
|
||||
val reference = expression.callableReference
|
||||
|
||||
val resolved = BooleanArray(1)
|
||||
val descriptor = resolveCallableReferenceTarget(expression, lhsType, context, resolved, callResolver)
|
||||
if (!resolved[0]) {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(reference, reference))
|
||||
}
|
||||
if (descriptor == null) return null
|
||||
|
||||
if (expression.typeReference == null &&
|
||||
(descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) {
|
||||
context.trace.report(CALLABLE_REFERENCE_TO_MEMBER_OR_EXTENSION_WITH_EMPTY_LHS.on(reference))
|
||||
}
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
if (DescriptorUtils.isObject(containingDeclaration)) {
|
||||
context.trace.report(CALLABLE_REFERENCE_TO_OBJECT_MEMBER.on(reference))
|
||||
}
|
||||
if (descriptor is ConstructorDescriptor && DescriptorUtils.isAnnotationClass(containingDeclaration)) {
|
||||
context.trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(reference))
|
||||
}
|
||||
|
||||
return createReflectionTypeForResolvedCallableReference(expression, lhsType, descriptor, context, reflectionTypes)
|
||||
}
|
||||
}
|
||||
+6
@@ -46,6 +46,7 @@ public class ExpressionTypingComponents {
|
||||
/*package*/ LocalClassifierAnalyzer localClassifierAnalyzer;
|
||||
/*package*/ FunctionDescriptorResolver functionDescriptorResolver;
|
||||
/*package*/ CallExpressionResolver callExpressionResolver;
|
||||
/*package*/ DoubleColonExpressionResolver doubleColonExpressionResolver;
|
||||
/*package*/ DescriptorResolver descriptorResolver;
|
||||
/*package*/ TypeResolver typeResolver;
|
||||
/*package*/ AnnotationResolver annotationResolver;
|
||||
@@ -126,6 +127,11 @@ public class ExpressionTypingComponents {
|
||||
this.callExpressionResolver = callExpressionResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDoubleColonExpressionResolver(DoubleColonExpressionResolver doubleColonExpressionResolver) {
|
||||
this.doubleColonExpressionResolver = doubleColonExpressionResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDescriptorResolver(DescriptorResolver descriptorResolver) {
|
||||
this.descriptorResolver = descriptorResolver;
|
||||
|
||||
Reference in New Issue
Block a user