diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 0d88108cb16..886dc03614f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -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 arguments = - CollectionsKt.map(typeConstructor.getParameters(), new Function1() { - @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 parameters = typeConstructor.getParameters(); - if (parameters.size() != type.getArguments().size()) return false; - - Iterator 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 resolutionResult = - components.callExpressionResolver.resolveSimpleName(c.replaceTraceAndCache(traceAndCache), simpleNameExpression); - - Collection> resultingCalls = - CollectionsKt.filter(resolutionResult.getResultingCalls(), new Function1, Boolean>() { - @Override - public Boolean invoke(ResolvedCall 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, VariableDescriptor>() { - @Override - public VariableDescriptor invoke(ResolvedCall 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; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt new file mode 100644 index 00000000000..6afe5cb5cea --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -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) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java index b28f7c5e4be..6d2746f4348 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingComponents.java @@ -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;