Drop createQualifier.

NB: some regression in diagnostics for special cases,
such as class or package used in expression position or in safe access;
see next commit.
This commit is contained in:
Dmitry Petrov
2015-11-11 16:43:29 +03:00
parent b532fa2bbf
commit 28d15e776a
5 changed files with 116 additions and 110 deletions
@@ -23,65 +23,54 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassObjectType
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassifierQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ClassifierQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
public fun resolveAsReceiverInQualifiedExpression( public fun resolveQualifierAsReceiverInExpression(
qualifier: QualifierReceiver, qualifier: Qualifier,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?, selector: DeclarationDescriptor?,
symbolUsageValidator: SymbolUsageValidator
) {
resolveAndRecordReferenceTarget(qualifier, context, selector, symbolUsageValidator)
if (qualifier is ClassifierQualifier) {
val classifier = qualifier.classifier
if (classifier is TypeParameterDescriptor) {
context.trace.report(Errors.TYPE_PARAMETER_ON_LHS_OF_DOT.on(qualifier.referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && classifier.hasClassObjectType) {
context.trace.recordType(qualifier.expression, classifier.classObjectType)
}
}
}
public fun resolveAsStandaloneExpression(
qualifier: QualifierReceiver,
context: ExpressionTypingContext, context: ExpressionTypingContext,
symbolUsageValidator: SymbolUsageValidator symbolUsageValidator: SymbolUsageValidator
) { ): DeclarationDescriptor {
resolveAndRecordReferenceTarget(qualifier, context, selector = null, symbolUsageValidator = symbolUsageValidator) val referenceTarget = resolveQualifierReferenceTarget(qualifier, selector, context, symbolUsageValidator)
if (qualifier is ClassifierQualifier) { if (referenceTarget is TypeParameterDescriptor) {
val classifier = qualifier.classifier context.trace.report(Errors.TYPE_PARAMETER_ON_LHS_OF_DOT.on(qualifier.referenceExpression, referenceTarget))
if (classifier is TypeParameterDescriptor) {
context.trace.report(Errors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(qualifier.referenceExpression, classifier))
}
else if (classifier is ClassDescriptor && !classifier.hasClassObjectType) {
context.trace.report(Errors.NO_COMPANION_OBJECT.on(qualifier.referenceExpression, classifier))
}
}
else if (qualifier is PackageQualifier) {
context.trace.report(Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND.on(qualifier.referenceExpression))
} }
return referenceTarget
} }
private fun resolveAndRecordReferenceTarget( public fun resolveQualifierAsStandaloneExpression(
qualifier: QualifierReceiver, qualifier: Qualifier,
context: ExpressionTypingContext, context: ExpressionTypingContext,
selector: DeclarationDescriptor?,
symbolUsageValidator: SymbolUsageValidator symbolUsageValidator: SymbolUsageValidator
) { ): DeclarationDescriptor {
val resultingDescriptor = resolveReferenceTarget(qualifier, context, selector, symbolUsageValidator) val referenceTarget = resolveQualifierReferenceTarget(qualifier, null, context, symbolUsageValidator)
context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, resultingDescriptor)
when (referenceTarget) {
is TypeParameterDescriptor -> {
context.trace.report(Errors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION.on(qualifier.referenceExpression, referenceTarget))
}
is ClassDescriptor -> {
if (!referenceTarget.kind.isSingleton) {
context.trace.report(Errors.NO_COMPANION_OBJECT.on(qualifier.referenceExpression, referenceTarget))
}
}
is PackageViewDescriptor -> {
context.trace.report(Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND.on(qualifier.referenceExpression))
}
}
return referenceTarget
} }
private fun resolveReferenceTarget( private fun resolveQualifierReferenceTarget(
qualifier: QualifierReceiver, qualifier: Qualifier,
context: ExpressionTypingContext,
selector: DeclarationDescriptor?, selector: DeclarationDescriptor?,
context: ExpressionTypingContext,
symbolUsageValidator: SymbolUsageValidator symbolUsageValidator: SymbolUsageValidator
): DeclarationDescriptor { ): DeclarationDescriptor {
if (qualifier is ClassifierQualifier && qualifier.classifier is TypeParameterDescriptor) { if (qualifier is ClassifierQualifier && qualifier.classifier is TypeParameterDescriptor) {
@@ -102,15 +91,19 @@ private fun resolveReferenceTarget(
return qualifier.packageView return qualifier.packageView
} }
// TODO make decisions about short reference to companion object somewhere else
if (qualifier is ClassQualifier) { if (qualifier is ClassQualifier) {
val classifier = qualifier.classifier
if (selector is CallableDescriptor && if (selector is CallableDescriptor &&
(selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) && (selector.dispatchReceiverParameter != null || selector.extensionReceiverParameter != null) &&
qualifier.classifier is ClassDescriptor && classifier is ClassDescriptor &&
qualifier.classifier.hasClassObjectType classifier.hasClassObjectType
) { ) {
val companionObjectDescriptor = qualifier.classifier.companionObjectDescriptor val companionObjectDescriptor = classifier.companionObjectDescriptor
if (companionObjectDescriptor != null) { if (companionObjectDescriptor != null) {
context.trace.record(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, qualifier.referenceExpression, qualifier.classifier) context.trace.record(BindingContext.REFERENCE_TARGET, qualifier.referenceExpression, companionObjectDescriptor)
context.trace.record(BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, qualifier.referenceExpression, classifier)
context.trace.recordType(qualifier.expression, classifier.classObjectType)
symbolUsageValidator.validateTypeUsage(companionObjectDescriptor, context.trace, qualifier.referenceExpression) symbolUsageValidator.validateTypeUsage(companionObjectDescriptor, context.trace, qualifier.referenceExpression)
return companionObjectDescriptor return companionObjectDescriptor
} }
@@ -28,14 +28,11 @@ import org.jetbrains.kotlin.resolve.calls.unrollToLeftMostQualifiedExpression
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.utils.*
import org.jetbrains.kotlin.resolve.scopes.receivers.createClassifierQualifier
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.check
@@ -392,6 +389,33 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
return Pair(currentDescriptor, path.size) return Pair(currentDescriptor, path.size)
} }
public fun resolveNameExpressionAsQualifierForDiagnostics(
expression: KtSimpleNameExpression,
receiver: Receiver,
context: ExpressionTypingContext
): Qualifier? {
val name = expression.getReferencedNameAsName()
val qualifierDescriptor = when {
receiver is PackageQualifier -> {
val childPackageFQN = receiver.packageView.fqName.child(name)
val childPackageDescriptor = receiver.packageView.module.getPackage(childPackageFQN).check { !it.isEmpty() }
childPackageDescriptor ?: receiver.packageView.memberScope.getContributedClassifier(name, KotlinLookupLocation(expression))
}
receiver is ClassQualifier ->
receiver.scope.getContributedClassifier(name, KotlinLookupLocation(expression))
!receiver.exists() ->
context.scope.findClassifier(name, KotlinLookupLocation(expression)) ?:
context.scope.ownerDescriptor.module.getPackage(FqName.ROOT.child(name)).check { !it.isEmpty() }
else -> null
}
if (qualifierDescriptor != null) {
return storeResult(context.trace, expression, qualifierDescriptor, context.scope.ownerDescriptor, QualifierPosition.EXPRESSION)
}
return null
}
public fun resolveQualifierInExpressionAndUnroll( public fun resolveQualifierInExpressionAndUnroll(
expression: KtQualifiedExpression, expression: KtQualifiedExpression,
@@ -411,11 +435,11 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
isValue = isValue isValue = isValue
).second ).second
val firstExpressionAfterQualifierIndex = val nextExpressionIndexAfterQualifier =
if (nextIndexAfterPrefix == 0) 0 else nextIndexAfterPrefix - 1 if (nextIndexAfterPrefix == 0) 0 else nextIndexAfterPrefix - 1
return qualifiedExpressions return qualifiedExpressions
.subList(firstExpressionAfterQualifierIndex, qualifiedExpressions.size) .subList(nextExpressionIndexAfterQualifier, qualifiedExpressions.size)
.map { CallExpressionElement(it) } .map { CallExpressionElement(it) }
} }
@@ -520,10 +544,10 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
shouldBeVisibleFrom: DeclarationDescriptor?, shouldBeVisibleFrom: DeclarationDescriptor?,
position: QualifierPosition, position: QualifierPosition,
isQualifier: Boolean = true isQualifier: Boolean = true
) { ): Qualifier? {
if (descriptor == null) { if (descriptor == null) {
trace.report(Errors.UNRESOLVED_REFERENCE.on(referenceExpression, referenceExpression)) trace.report(Errors.UNRESOLVED_REFERENCE.on(referenceExpression, referenceExpression))
return return null
} }
trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptor) trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptor)
@@ -545,20 +569,20 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
} }
} }
if (isQualifier) { return if (isQualifier) storeQualifier(trace, referenceExpression, descriptor) else null
storeQualifier(trace, referenceExpression, descriptor)
}
} }
private fun storeQualifier(trace: BindingTrace, referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor) { private fun storeQualifier(trace: BindingTrace, referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor): Qualifier? {
val qualifier = val qualifier =
when (descriptor) { when (descriptor) {
is PackageViewDescriptor -> PackageQualifier(referenceExpression, descriptor) is PackageViewDescriptor -> PackageQualifier(referenceExpression, descriptor)
is ClassifierDescriptor -> createClassifierQualifier(referenceExpression, descriptor, trace.bindingContext) is ClassifierDescriptor -> createClassifierQualifier(referenceExpression, descriptor, trace.bindingContext)
else -> return else -> return null
} }
trace.record(BindingContext.QUALIFIER, qualifier.expression, qualifier) trace.record(BindingContext.QUALIFIER, qualifier.expression, qualifier)
return qualifier
} }
private fun isVisible( private fun isVisible(
@@ -127,8 +127,9 @@ public class CallExpressionResolver {
// if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved // if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
boolean isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression); boolean isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression);
if (!resolutionResult.isNothing() && resolutionResult.getResultCode() != OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER) { if (!resolutionResult.isNothing() && resolutionResult.getResultCode() != OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER) {
boolean isQualifier = isLHSOfDot && resolutionResult.isSingleResult() boolean isQualifier = isLHSOfDot &&
&& resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject; resolutionResult.isSingleResult() &&
resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject;
if (!isQualifier) { if (!isQualifier) {
result[0] = true; result[0] = true;
temporaryForVariable.commit(); temporaryForVariable.commit();
@@ -136,14 +137,13 @@ public class CallExpressionResolver {
} }
} }
QualifierReceiver qualifier = QualifierKt.createQualifier(nameExpression, receiver, context); //// Generate some diagnostics for qualifier in unexpected position
if (qualifier != null) { //DeclarationDescriptor qualifierDescriptor =
result[0] = true; // QualifiedExpressionResolveUtilKt.getQualifierDescriptorOrNull(nameExpression, receiver, context);
if (!isLHSOfDot) { //if (qualifierDescriptor != null) {
QualifiedExpressionResolveUtilKt.resolveAsStandaloneExpression(qualifier, context, symbolUsageValidator); // QualifiedExpressionResolveUtilKt.checkQualifierAsStandaloneExpression(qualifierDescriptor, nameExpression, context);
} //}
return null;
}
temporaryForVariable.commit(); temporaryForVariable.commit();
result[0] = !resolutionResult.isNothing(); result[0] = !resolutionResult.isNothing();
return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null; return resolutionResult.isSingleResult() ? resolutionResult.getResultingDescriptor().getReturnType() : null;
@@ -191,6 +191,15 @@ public class CallExpressionResolver {
return TypeInfoFactoryKt.createTypeInfo(type, context); return TypeInfoFactoryKt.createTypeInfo(type, context);
} }
TemporaryTraceAndCache temporaryForQualifier = TemporaryTraceAndCache.create(context, "trace to resolve as qualifier", nameExpression);
ExpressionTypingContext contextForQualifier = context.replaceTraceAndCache(temporaryForQualifier);
Qualifier qualifier = qualifiedExpressionResolver.resolveNameExpressionAsQualifierForDiagnostics(nameExpression, receiver, contextForQualifier);
if (qualifier != null) {
QualifiedExpressionResolveUtilKt.resolveQualifierAsStandaloneExpression(qualifier, contextForQualifier, symbolUsageValidator);
temporaryForQualifier.commit();
return TypeInfoFactoryKt.createTypeInfo(null, context);
}
temporaryForVariable.commit(); temporaryForVariable.commit();
return TypeInfoFactoryKt.noTypeInfo(context); return TypeInfoFactoryKt.noTypeInfo(context);
} }
@@ -350,7 +359,9 @@ public class CallExpressionResolver {
return false; return false;
} }
return !resolutionResult.isNothing(); OverloadResolutionResults.Code resultCode = resolutionResult.getResultCode();
return resultCode != OverloadResolutionResults.Code.NAME_NOT_FOUND &&
resultCode != OverloadResolutionResults.Code.CANDIDATES_WITH_WRONG_RECEIVER;
} }
}; };
List<CallExpressionElement> elementChain = List<CallExpressionElement> elementChain =
@@ -462,7 +473,7 @@ public class CallExpressionResolver {
calleeExpression instanceof KtReferenceExpression calleeExpression instanceof KtReferenceExpression
? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null; ? context.trace.get(BindingContext.REFERENCE_TARGET, (KtReferenceExpression) calleeExpression) : null;
QualifiedExpressionResolveUtilKt.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor, symbolUsageValidator); QualifiedExpressionResolveUtilKt.resolveQualifierAsReceiverInExpression(qualifierReceiver, selectorDescriptor, context, symbolUsageValidator);
} }
private static void checkNestedClassAccess( private static void checkNestedClassAccess(
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.calls.tasks.collectors package org.jetbrains.kotlin.resolve.calls.tasks.collectors
import com.intellij.util.SmartList
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -33,6 +34,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.*
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addIfNotNull
public interface CallableDescriptorCollector<D : CallableDescriptor> { public interface CallableDescriptorCollector<D : CallableDescriptor> {
@@ -165,7 +167,10 @@ private object FunctionCollector : CallableDescriptorCollector<FunctionDescripto
private object VariableCollector : CallableDescriptorCollector<VariableDescriptor> { private object VariableCollector : CallableDescriptorCollector<VariableDescriptor> {
override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> { override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
return listOfNotNull(lexicalScope.findLocalVariable(name)) val result = SmartList<VariableDescriptor>()
result.addIfNotNull(lexicalScope.findLocalVariable(name))
result.addIfNotNull(getContributedFakeDescriptorForObject(lexicalScope, name, location))
return result
} }
override fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> { override fun getStaticInheritanceByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
@@ -179,7 +184,13 @@ private object VariableCollector : CallableDescriptorCollector<VariableDescripto
} }
} }
private fun getFakeDescriptorForObject(scope: HierarchicalScope, name: Name, location: LookupLocation): VariableDescriptor? { private fun getContributedFakeDescriptorForObject(scope: LexicalScope, name: Name, location: LookupLocation): VariableDescriptor? {
val classifier = scope.getContributedClassifier(name, location)
if (classifier !is ClassDescriptor || !classifier.hasClassObjectType) return null
return FakeCallableDescriptorForObject(classifier)
}
private fun findFakeDescriptorForObject(scope: HierarchicalScope, name: Name, location: LookupLocation): VariableDescriptor? {
val classifier = scope.findClassifier(name, location) val classifier = scope.findClassifier(name, location)
if (classifier !is ClassDescriptor || !classifier.hasCompanionObject) return null if (classifier !is ClassDescriptor || !classifier.hasCompanionObject) return null
@@ -188,14 +199,14 @@ private object VariableCollector : CallableDescriptorCollector<VariableDescripto
override fun getNonExtensionsByName(scope: HierarchicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> { override fun getNonExtensionsByName(scope: HierarchicalScope, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
val properties = scope.collectVariables(name, location).filter { it.extensionReceiverParameter == null } val properties = scope.collectVariables(name, location).filter { it.extensionReceiverParameter == null }
val fakeDescriptor = getFakeDescriptorForObject(scope, name, location) val fakeDescriptor = findFakeDescriptorForObject(scope, name, location)
return if (fakeDescriptor != null) properties + fakeDescriptor else properties return if (fakeDescriptor != null) properties + fakeDescriptor else properties
} }
override fun getMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<VariableDescriptor> { override fun getMembersByName(receiver: KotlinType, name: Name, location: LookupLocation): Collection<VariableDescriptor> {
val memberScope = receiver.memberScope val memberScope = receiver.memberScope
val properties = memberScope.getContributedVariables(name, location) val properties = memberScope.getContributedVariables(name, location)
val fakeDescriptor = getFakeDescriptorForObject(memberScope.memberScopeAsImportingScope(), name, location) val fakeDescriptor = findFakeDescriptorForObject(memberScope.memberScopeAsImportingScope(), name, location)
return if (fakeDescriptor != null) properties + fakeDescriptor else properties return if (fakeDescriptor != null) properties + fakeDescriptor else properties
} }
@@ -149,39 +149,6 @@ class ClassQualifier(
override fun toString() = "Class{$classifier}" override fun toString() = "Class{$classifier}"
} }
fun createQualifier(expression: KtSimpleNameExpression, receiver: Receiver, context: ExpressionTypingContext): QualifierReceiver? {
val receiverScope = when {
!receiver.exists() -> context.scope
receiver is QualifierReceiver -> receiver.scope.memberScopeAsImportingScope()
receiver is ReceiverValue -> receiver.type.memberScope.memberScopeAsImportingScope()
else -> throw IllegalArgumentException("Unexpected receiver kind: $receiver")
}
val name = expression.getReferencedNameAsName()
val packageViewDescriptor = receiverScope.findPackage(name)
val classifierDescriptor = receiverScope.findClassifier(name, KotlinLookupLocation(expression))
if (packageViewDescriptor == null && classifierDescriptor == null) return null
context.trace.recordScope(context.scope, expression)
val qualifier =
if (receiver is PackageQualifier) {
if (packageViewDescriptor != null)
PackageQualifier(expression, packageViewDescriptor)
else
createClassifierQualifier(expression, classifierDescriptor!!, context.trace.bindingContext)
else
if (classifierDescriptor != null)
createClassifierQualifier(expression, classifierDescriptor, context.trace.bindingContext)
else
PackageQualifier(expression, packageViewDescriptor!!)
}
context.trace.record(QUALIFIER, qualifier.expression, qualifier)
return qualifier
}
fun createClassifierQualifier( fun createClassifierQualifier(
referenceExpression: KtSimpleNameExpression, referenceExpression: KtSimpleNameExpression,
classifier: ClassifierDescriptor, classifier: ClassifierDescriptor,