Support for new double colon expressions in type checker

Despite the fact that the LHS of a double colon expression is now KtExpression
instead of KtUserType, we must still consider it a type for callable references
to work. Extract and reuse relevant parts of QualifiedExpressionResolver and
TypeResolver to support this behavior
This commit is contained in:
Alexander Udalov
2016-04-21 18:44:07 +03:00
parent b5388d6a43
commit 693c753988
16 changed files with 445 additions and 107 deletions
@@ -22,6 +22,20 @@ import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.lexer.KtTokens
abstract class KtDoubleColonExpression(node: ASTNode) : KtExpressionImpl(node) {
val receiverExpression: KtExpression?
get() = node.firstChildNode.psi as? KtExpression
val hasQuestionMarks: Boolean
get() {
for (element in generateSequence(node.firstChildNode, ASTNode::getTreeNext)) {
when (element.elementType) {
KtTokens.QUEST -> return true
KtTokens.COLONCOLON -> return false
}
}
error("Double colon expression must have '::': $text")
}
val typeReference: KtTypeReference?
get() = findChildByType(KtNodeTypes.TYPE_REFERENCE)
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier;
import org.jetbrains.kotlin.types.DeferredType;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.expressions.CaptureKind;
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo;
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor;
import org.jetbrains.kotlin.util.Box;
@@ -102,6 +103,8 @@ public interface BindingContext {
*/
WritableSlice<KtExpression, Qualifier> QUALIFIER = new BasicWritableSlice<KtExpression, Qualifier>(DO_NOTHING);
WritableSlice<KtExpression, DoubleColonLHS> DOUBLE_COLON_LHS = new BasicWritableSlice<KtExpression, DoubleColonLHS>(DO_NOTHING);
WritableSlice<KtSuperExpression, KotlinType> THIS_TYPE_FOR_SUPER_EXPRESSION =
new BasicWritableSlice<KtSuperExpression, KotlinType>(DO_NOTHING);
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
import org.jetbrains.kotlin.types.expressions.isWithoutValueArguments
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.check
@@ -69,7 +70,7 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator
isDebuggerContext: Boolean
): TypeQualifierResolutionResult {
val ownerDescriptor = if (!isDebuggerContext) scope.ownerDescriptor else null
if (userType.qualifier == null && !userType.startWithPackage) { // optimization for non-qualified types
if (userType.qualifier == null && !userType.startWithPackage) {
val descriptor = userType.referenceExpression?.let {
val classifier = scope.findClassifier(it.getReferencedNameAsName(), KotlinLookupLocation(it))
storeResult(trace, it, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false)
@@ -87,13 +88,25 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator
) as? ClassifierDescriptor
return TypeQualifierResolutionResult(qualifierPartList, descriptor)
}
assert(qualifierPartList.size >= 1) {
"Too short qualifier list for user type $userType : ${qualifierPartList.joinToString()}"
}
return resolveQualifierPartListForType(
qualifierPartList, ownerDescriptor, module, scope.check { !userType.startWithPackage }, trace, isQualifier = false
)
}
private fun resolveQualifierPartListForType(
qualifierPartList: List<QualifierPart>,
ownerDescriptor: DeclarationDescriptor?,
module: ModuleDescriptor,
scope: LexicalScope?,
trace: BindingTrace,
isQualifier: Boolean
): TypeQualifierResolutionResult {
assert(qualifierPartList.isNotEmpty()) { "Qualifier list should not be empty" }
val qualifier = resolveToPackageOrClass(
qualifierPartList.subList(0, qualifierPartList.size - 1), module,
trace, ownerDescriptor, scope.check { !userType.startWithPackage }, position = QualifierPosition.TYPE
qualifierPartList.subList(0, qualifierPartList.size - 1), module, trace, ownerDescriptor, scope,
position = QualifierPosition.TYPE
) ?: return TypeQualifierResolutionResult(qualifierPartList, null)
val lastPart = qualifierPartList.last()
@@ -102,10 +115,36 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator
is ClassDescriptor -> qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location)
else -> null
}
storeResult(trace, lastPart.expression, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false)
storeResult(trace, lastPart.expression, classifier, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = isQualifier)
return TypeQualifierResolutionResult(qualifierPartList, classifier)
}
fun resolveDescriptorForDoubleColonLHS(
expression: KtExpression,
scope: LexicalScope,
trace: BindingTrace,
isDebuggerContext: Boolean
): TypeQualifierResolutionResult {
val ownerDescriptor = if (!isDebuggerContext) scope.ownerDescriptor else null
val qualifierPartList = expression.asQualifierPartList(doubleColonLHS = true)
if (qualifierPartList.isEmpty()) {
return TypeQualifierResolutionResult(qualifierPartList, null)
}
if (qualifierPartList.size == 1) {
val (name, simpleName) = qualifierPartList.single()
val descriptor = scope.findClassifier(name, KotlinLookupLocation(simpleName))
storeResult(trace, simpleName, descriptor, ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = true)
return TypeQualifierResolutionResult(qualifierPartList, descriptor)
}
return resolveQualifierPartListForType(
qualifierPartList, ownerDescriptor, scope.ownerDescriptor.module, scope, trace, isQualifier = true
)
}
private val KtUserType.startWithPackage: Boolean
get() {
var firstPart = this
@@ -270,24 +309,32 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator
storeResult(trace, lastPart.expression, descriptors, shouldBeVisibleFrom = null, position = QualifierPosition.IMPORT, isQualifier = false)
}
private fun KtExpression.asQualifierPartList(): List<QualifierPart> {
private fun KtExpression.asQualifierPartList(doubleColonLHS: Boolean = false): List<QualifierPart> {
val result = SmartList<QualifierPart>()
var expression: KtExpression? = this
loop@ while (expression != null) {
when (expression) {
is KtSimpleNameExpression -> {
result.add(QualifierPart(expression.getReferencedNameAsName(), expression))
break@loop
}
is KtQualifiedExpression -> {
(expression.selectorExpression as? KtSimpleNameExpression)?.let {
result.add(QualifierPart(it.getReferencedNameAsName(), it))
}
expression = expression.receiverExpression
}
else -> expression = null
fun addQualifierPart(expression: KtExpression?): Boolean {
if (expression is KtSimpleNameExpression) {
result.add(QualifierPart(expression))
return true
}
if (doubleColonLHS && expression is KtCallExpression && expression.isWithoutValueArguments) {
val simpleName = expression.calleeExpression as KtSimpleNameExpression
result.add(QualifierPart(simpleName.getReferencedNameAsName(), simpleName, expression.typeArgumentList))
return true
}
return false
}
var expression: KtExpression? = this
while (true) {
if (addQualifierPart(expression)) break
if (expression !is KtQualifiedExpression) break
addQualifierPart(expression.selectorExpression)
expression = expression.receiverExpression
}
return result.asReversed()
}
@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Variance.*
import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing
import java.util.*
class TypeResolver(
private val annotationResolver: AnnotationResolver,
@@ -163,37 +162,21 @@ class TypeResolver(
var result: PossiblyBareType? = null
typeElement?.accept(object : KtVisitorVoid() {
override fun visitUserType(type: KtUserType) {
val qualifierResolutionResults = resolveDescriptorForType(c.scope, type, c.trace, c.isDebuggerContext)
val (qualifierParts, classifierDescriptor) = qualifierResolutionResults
val qualifierResolutionResult = resolveDescriptorForType(c.scope, type, c.trace, c.isDebuggerContext)
val classifier = qualifierResolutionResult.classifierDescriptor
if (classifierDescriptor == null) {
if (classifier == null) {
val arguments = resolveTypeProjections(
c, ErrorUtils.createErrorType("No type").constructor, qualifierResolutionResults.allProjections)
c, ErrorUtils.createErrorType("No type").constructor, qualifierResolutionResult.allProjections
)
result = type(ErrorUtils.createErrorTypeWithArguments(type.getDebugText(), arguments))
return
}
val referenceExpression = type.getReferenceExpression()
val referencedName = type.getReferencedName()
if (referenceExpression == null || referencedName == null) return
val referenceExpression = type.referenceExpression ?: return
c.trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classifier)
c.trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, classifierDescriptor)
result = when (classifierDescriptor) {
is TypeParameterDescriptor -> {
assert(qualifierParts.size == 1) {
"Type parameter can be resolved only by it's short name, but '${type.text}' is contradiction " +
"with ${qualifierParts.size} qualifier parts"
}
type(resolveTypeForTypeParameter(c, annotations, classifierDescriptor, referenceExpression, type))
}
is ClassDescriptor ->
resolveTypeForClass(c, annotations, classifierDescriptor, type, qualifierResolutionResults)
is TypeAliasDescriptor ->
resolveTypeForTypeAlias(c, annotations, classifierDescriptor, type, qualifierResolutionResults)
else -> error("Unexpected classifier type: ${classifierDescriptor.javaClass}")
}
result = resolveTypeForClassifier(c, classifier, qualifierResolutionResult, type, annotations)
}
override fun visitNullableType(nullableType: KtNullableType) {
@@ -308,13 +291,13 @@ class TypeResolver(
c: TypeResolutionContext, annotations: Annotations,
typeParameter: TypeParameterDescriptor,
referenceExpression: KtSimpleNameExpression,
type: KtUserType
typeArgumentList: KtTypeArgumentList?
): KotlinType {
val scopeForTypeParameter = getScopeForTypeParameter(c, typeParameter)
val arguments = resolveTypeProjections(c, ErrorUtils.createErrorType("No type").constructor, type.typeArguments)
if (!arguments.isEmpty()) {
c.trace.report(TYPE_ARGUMENTS_NOT_ALLOWED.on(type.typeArgumentList!!, "for type parameters"))
if (typeArgumentList != null) {
resolveTypeProjections(c, ErrorUtils.createErrorType("No type").constructor, typeArgumentList.arguments)
c.trace.report(TYPE_ARGUMENTS_NOT_ALLOWED.on(typeArgumentList, "for type parameters"))
}
val containing = typeParameter.containingDeclaration
@@ -342,9 +325,34 @@ class TypeResolver(
}
}
fun resolveTypeForClassifier(
c: TypeResolutionContext,
descriptor: ClassifierDescriptor,
qualifierResolutionResult: QualifiedExpressionResolver.TypeQualifierResolutionResult,
element: KtElement,
annotations: Annotations
): PossiblyBareType {
val qualifierParts = qualifierResolutionResult.qualifierParts
return when (descriptor) {
is TypeParameterDescriptor -> {
assert(qualifierParts.size == 1) {
"Type parameter can be resolved only by it's short name, but '${element.text}' is contradiction " +
"with ${qualifierParts.size} qualifier parts"
}
val qualifierPart = qualifierParts.single()
type(resolveTypeForTypeParameter(c, annotations, descriptor, qualifierPart.expression, qualifierPart.typeArguments))
}
is ClassDescriptor -> resolveTypeForClass(c, annotations, descriptor, element, qualifierResolutionResult)
is TypeAliasDescriptor -> resolveTypeForTypeAlias(c, annotations, descriptor, element as KtUserType /* TODO */, qualifierResolutionResult)
else -> error("Unexpected classifier type: ${descriptor.javaClass}")
}
}
private fun resolveTypeForClass(
c: TypeResolutionContext, annotations: Annotations,
classDescriptor: ClassDescriptor, type: KtUserType,
classDescriptor: ClassDescriptor, element: KtElement,
qualifierResolutionResult: QualifiedExpressionResolver.TypeQualifierResolutionResult
): PossiblyBareType {
val typeConstructor = classDescriptor.typeConstructor
@@ -366,7 +374,7 @@ class TypeResolver(
assert(collectedArgumentAsTypeProjections.size <= parameters.size) {
"Collected arguments count should be not greater then parameters count," +
" but ${collectedArgumentAsTypeProjections.size} instead of ${parameters.size} found in ${type.text}"
" but ${collectedArgumentAsTypeProjections.size} instead of ${parameters.size} found in ${element.text}"
}
val argumentsFromUserType = resolveTypeProjections(c, typeConstructor, collectedArgumentAsTypeProjections)
@@ -374,7 +382,7 @@ class TypeResolver(
assert(arguments.size == parameters.size) {
"Collected arguments count should be equal to parameters count," +
" but ${collectedArgumentAsTypeProjections.size} instead of ${parameters.size} found in ${type.text}"
" but ${collectedArgumentAsTypeProjections.size} instead of ${parameters.size} found in ${element.text}"
}
val resultingType = KotlinTypeImpl.create(annotations, classDescriptor, false, arguments)
@@ -397,7 +405,7 @@ class TypeResolver(
}
if (resultingType.isArrayOfNothing()) {
c.trace.report(UNSUPPORTED.on(type, "Array<Nothing> is illegal"))
c.trace.report(UNSUPPORTED.on(element, "Array<Nothing> is illegal"))
}
return type(resultingType)
@@ -783,10 +791,13 @@ class TypeResolver(
TypeProjectionImpl((it.original as TypeParameterDescriptor).defaultType)
}
private fun resolveTypeProjections(c: TypeResolutionContext, constructor: TypeConstructor, argumentElements: List<KtTypeProjection>): List<TypeProjection> {
fun resolveTypeProjections(
c: TypeResolutionContext,
constructor: TypeConstructor,
argumentElements: List<KtTypeProjection>
): List<TypeProjection> {
return argumentElements.mapIndexed { i, argumentElement ->
val projectionKind = argumentElement.getProjectionKind()
val projectionKind = argumentElement.projectionKind
ModifierCheckerCore.check(argumentElement, c.trace, null)
if (projectionKind == KtProjectionKind.STAR) {
val parameters = constructor.parameters
@@ -265,12 +265,13 @@ fun getReflectionTypeForCandidateDescriptor(
fun createReflectionTypeForResolvedCallableReference(
reference: KtCallableReferenceExpression,
lhsType: KotlinType?,
ignoreReceiver: Boolean,
descriptor: CallableDescriptor,
context: ResolutionContext<*>,
reflectionTypes: ReflectionTypes
): KotlinType? {
val type = createReflectionTypeForCallableDescriptor(
descriptor, lhsType, reflectionTypes, context.trace, reference.callableReference, reference.isEmptyLHS
descriptor, lhsType, reflectionTypes, context.trace, reference.callableReference, ignoreReceiver
) ?: return null
when (descriptor) {
is FunctionDescriptor -> {
@@ -24,13 +24,9 @@ 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.psi.*
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.callableReferences.createReflectionTypeForResolvedCallableReference
import org.jetbrains.kotlin.resolve.callableReferences.resolveCallableReferenceTarget
import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver
@@ -43,63 +39,147 @@ 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
import javax.inject.Inject
// TODO: use a language level option
val BOUND_REFERENCES_ENABLED by lazy { System.getProperty("kotlin.lang.enable.bound.references") == "true" }
sealed class DoubleColonLHS(val type: KotlinType) {
class Expression(val typeInfo: KotlinTypeInfo) : DoubleColonLHS(typeInfo.type!!)
class Type(type: KotlinType, val possiblyBareType: PossiblyBareType) : DoubleColonLHS(type)
}
// Returns true if this expression has the form "A<B>" which means it's a type on the LHS of a double colon expression
internal val KtCallExpression.isWithoutValueArguments: Boolean
get() = valueArgumentList == null && lambdaArguments.isEmpty()
class DoubleColonExpressionResolver(
val callResolver: CallResolver,
val callExpressionResolver: CallExpressionResolver,
val qualifiedExpressionResolver: QualifiedExpressionResolver,
val dataFlowAnalyzer: DataFlowAnalyzer,
val reflectionTypes: ReflectionTypes,
val typeResolver: TypeResolver
) {
private lateinit var expressionTypingServices: ExpressionTypingServices
// component dependency cycle
@Inject
fun setExpressionTypingServices(expressionTypingServices: ExpressionTypingServices) {
this.expressionTypingServices = expressionTypingServices
}
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)
if (expression.isEmptyLHS) {
// "::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"))
}
else {
val result = resolveDoubleColonLHS(expression.receiverExpression!!, expression, c)
val type = result?.type
if (type != null && !type.isError) {
checkClassLiteral(c, expression, result!!)
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? {
if (expression.isEmptyLHS) {
// "::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
}
private fun checkClassLiteral(c: ExpressionTypingContext, expression: KtClassLiteralExpression, result: DoubleColonLHS) {
if (result !is DoubleColonLHS.Type) return
val context = TypeResolutionContext(
c.scope, c.trace, /* checkBounds = */ false, /* allowBareTypes = */ true, /* isDebuggerContext = */ false
)
val possiblyBareType = typeResolver.resolvePossiblyBareType(context, expression.typeReference!!)
if (!possiblyBareType.isBare && possiblyBareType.actualType.isError) {
return null
}
var reportError = false
val type: KotlinType
if (possiblyBareType.isBare) {
val descriptor = possiblyBareType.bareTypeConstructor.declarationDescriptor as? ClassDescriptor
?: error("Only classes can produce bare types: $possiblyBareType")
if (KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
context.trace.report(ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT.on(expression))
val type = result.type
val reportError: Boolean
if (result.possiblyBareType.isBare) {
val descriptor = type.constructor.declarationDescriptor
if (descriptor is ClassDescriptor && KotlinBuiltIns.isNonPrimitiveArray(descriptor)) {
c.trace.report(ARRAY_CLASS_LITERAL_REQUIRES_ARGUMENT.on(expression))
}
type = KotlinTypeImpl.create(
Annotations.EMPTY, descriptor, possiblyBareType.isNullable,
descriptor.typeConstructor.parameters.map(TypeUtils::makeStarProjection)
)
reportError = false
}
else {
type = possiblyBareType.actualType
reportError = !isAllowedInClassLiteral(type)
}
if (type.isMarkedNullable || reportError) {
context.trace.report(CLASS_LITERAL_LHS_NOT_A_CLASS.on(expression))
c.trace.report(CLASS_LITERAL_LHS_NOT_A_CLASS.on(expression))
}
}
// Returns true if the expression is not a call expression without value arguments (such as "A<B>") or a qualified expression
// which contains such call expression as one of its parts.
// In this case it's pointless to attempt to type check an expression on the LHS in "A<B>::class", since "A<B>" certainly means a type.
private fun KtExpression.canBeConsideredProperExpression(): Boolean {
return when (this) {
is KtCallExpression ->
!isWithoutValueArguments
is KtDotQualifiedExpression ->
receiverExpression.canBeConsideredProperExpression() &&
selectorExpression?.let { it.canBeConsideredProperExpression() } ?: false
else -> true
}
}
private fun resolveDoubleColonLHS(
expression: KtExpression, doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext
): DoubleColonLHS? {
// First, try resolving the LHS as expression, if possible
if (BOUND_REFERENCES_ENABLED && expression.canBeConsideredProperExpression() &&
!doubleColonExpression.hasQuestionMarks /* TODO: test this */) {
val traceForExpr = TemporaryTraceAndCache.create(c, "resolve '::' LHS as expression", expression)
val contextForExpr = c.replaceTraceAndCache(traceForExpr)
val typeInfo = expressionTypingServices.getTypeInfo(expression, contextForExpr)
val type = typeInfo.type
// TODO (!!!): it's wrong to only check type, should check that there's a companion qualifier
if (type != null && !DescriptorUtils.isCompanionObject(type.constructor.declarationDescriptor)) {
traceForExpr.commit()
return DoubleColonLHS.Expression(typeInfo).apply {
c.trace.record(BindingContext.DOUBLE_COLON_LHS, expression, this)
}
}
}
return type
// Then, try resolving it as type
val qualifierResolutionResult =
qualifiedExpressionResolver.resolveDescriptorForDoubleColonLHS(expression, c.scope, c.trace, c.isDebuggerContext)
val typeResolutionContext = TypeResolutionContext(
c.scope, c.trace, /* checkBounds = */ true, /* allowBareTypes = */ true,
/* isDebuggerContext = */ expression.suppressDiagnosticsInDebugMode() /* TODO: test this */
)
val classifier = qualifierResolutionResult.classifierDescriptor
if (classifier == null) {
typeResolver.resolveTypeProjections(
typeResolutionContext, ErrorUtils.createErrorType("No type").constructor, qualifierResolutionResult.allProjections
)
return null
}
val possiblyBareType = typeResolver.resolveTypeForClassifier(
typeResolutionContext, classifier, qualifierResolutionResult, expression, Annotations.EMPTY
)
val type = if (possiblyBareType.isBare) {
val descriptor = possiblyBareType.bareTypeConstructor.declarationDescriptor as? ClassDescriptor
?: error("Only classes can produce bare types: $possiblyBareType")
KotlinTypeImpl.create(
Annotations.EMPTY, descriptor, possiblyBareType.isNullable || doubleColonExpression.hasQuestionMarks,
descriptor.typeConstructor.parameters.map(TypeUtils::makeStarProjection)
)
}
else {
TypeUtils.makeNullableAsSpecified(possiblyBareType.actualType, doubleColonExpression.hasQuestionMarks)
}
return DoubleColonLHS.Type(type, possiblyBareType).apply {
c.trace.record(BindingContext.DOUBLE_COLON_LHS, expression, this)
}
}
private fun isAllowedInClassLiteral(type: KotlinType): Boolean {
@@ -122,11 +202,8 @@ class DoubleColonExpressionResolver(
}
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 lhs = expression.receiverExpression?.let { resolveDoubleColonLHS(it, expression, c) }
val receiverType = lhs?.type // TODO: handle .Expression and .Type
val callableReference = expression.callableReference
if (callableReference.getReferencedName().isEmpty()) {
@@ -136,7 +213,7 @@ class DoubleColonExpressionResolver(
}
val trace = TemporaryBindingTrace.create(c.trace, "Callable reference type")
val result = getCallableReferenceType(expression, receiverType, c.replaceBindingTrace(trace))
val result = getCallableReferenceType(expression, receiverType, lhs is DoubleColonLHS.Expression, c.replaceBindingTrace(trace))
val hasErrors = hasErrors(trace) // Do not inline this local variable (execution order is important)
trace.commit()
if (!hasErrors && result != null) {
@@ -181,6 +258,7 @@ class DoubleColonExpressionResolver(
private fun getCallableReferenceType(
expression: KtCallableReferenceExpression,
lhsType: KotlinType?,
isBound: Boolean,
context: ExpressionTypingContext
): KotlinType? {
val reference = expression.callableReference
@@ -205,6 +283,7 @@ class DoubleColonExpressionResolver(
context.trace.report(CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR.on(reference))
}
return createReflectionTypeForResolvedCallableReference(expression, lhsType, descriptor, context, reflectionTypes)
val ignoreReceiver = isBound || expression.isEmptyLHS
return createReflectionTypeForResolvedCallableReference(expression, lhsType, ignoreReceiver, descriptor, context, reflectionTypes)
}
}
@@ -0,0 +1,24 @@
// MODULE: m1
// FILE: 1.kt
package a
class b {
class c
}
// MODULE: m2
// FILE: 2.kt
package a.b
class c {
fun foo() {}
}
// MODULE: m3(m1, m2)
// FILE: test.kt
package test
fun test() = a.b.c::foo
@@ -0,0 +1,61 @@
// -- Module: <m1> --
package
package a {
public final class b {
public constructor b()
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()
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
}
}
}
// -- Module: <m2> --
package
package a {
package a.b {
public final class c {
public constructor c()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
}
// -- Module: <m3> --
package
package a {
public final class b {
// -- Module: <m1> --
}
package a.b {
public final class c {
// -- Module: <m2> --
}
}
}
package test {
public fun test(): kotlin.reflect.KFunction1<a.b.c, kotlin.Unit>
}
@@ -0,0 +1,16 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION
// FILE: simpleName.kt
package foo
fun test() {
<!UNRESOLVED_REFERENCE!>foo<!>::test
}
// FILE: qualifiedName.kt
package foo.bar
fun test() {
foo.<!UNRESOLVED_REFERENCE!>bar<!>::test
}
@@ -0,0 +1,9 @@
package
package foo {
public fun test(): kotlin.Unit
package foo.bar {
public fun test(): kotlin.Unit
}
}
@@ -0,0 +1,9 @@
package test
class Foo {
fun <T> bar(x: Int) = x
}
fun test() {
Foo::<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar<!> <!SYNTAX!>< <!DEBUG_INFO_MISSING_UNRESOLVED!>Int<!> ><!> <!SYNTAX!>(2 <!DEBUG_INFO_MISSING_UNRESOLVED!>+<!> 2)<!>
}
@@ -0,0 +1,13 @@
package
package test {
public fun test(): kotlin.Unit
public final class Foo {
public constructor Foo()
public final fun </*0*/ T> bar(/*0*/ x: kotlin.Int): kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -0,0 +1,16 @@
// !CHECK_TYPE
class Foo
fun Foo?.bar() {}
fun test() {
val r1 = Foo ?:: bar
checkSubtype<(Foo?) -> Unit>(r1)
val r2 = Foo ? :: bar
checkSubtype<(Foo?) -> Unit>(r2)
val r3 = Foo ? ? :: bar
checkSubtype<(Foo?) -> Unit>(r3)
}
@@ -0,0 +1,11 @@
package
public fun test(): kotlin.Unit
public fun Foo?.bar(): kotlin.Unit
public final class Foo {
public constructor Foo()
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
}
@@ -3,7 +3,7 @@
class A
val a1 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>A?::class<!>
val a2 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>A?<!REDUNDANT_NULLABLE!>?<!>::class<!>
val a2 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>A??::class<!>
val l1 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>List<String>?::class<!>
val l2 = <!CLASS_LITERAL_LHS_NOT_A_CLASS!>List?::class<!>
@@ -1653,6 +1653,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/callableReference"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("classVsPackage.kt")
public void testClassVsPackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/classVsPackage.kt");
doTest(fileName);
}
@TestMetadata("ea81649_errorPropertyLHS.kt")
public void testEa81649_errorPropertyLHS() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/ea81649_errorPropertyLHS.kt");
@@ -1677,12 +1683,30 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("packageInLhs.kt")
public void testPackageInLhs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/packageInLhs.kt");
doTest(fileName);
}
@TestMetadata("parsingPriorityOfGenericArgumentsVsLess.kt")
public void testParsingPriorityOfGenericArgumentsVsLess() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/parsingPriorityOfGenericArgumentsVsLess.kt");
doTest(fileName);
}
@TestMetadata("unused.kt")
public void testUnused() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/unused.kt");
doTest(fileName);
}
@TestMetadata("whitespacesInExpression.kt")
public void testWhitespacesInExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/tests/callableReference/function")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)