Make type aliases constructors return correct original descriptors
The problem was that when resolving super-calls we used known substitutor when creating a type alias constructor, thus its original return itself, while it's expected that it should return the descriptor before substitution The main idea of the fix that `createIfAvailable` should always return unsubstituted constructor. Note that known substitutor for type alias constructor should be based on abbreviation. The test change seems to be correct as PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE is already reported. Beside this, resolution behavior isn't expected to be changed dramatically
This commit is contained in:
@@ -4320,6 +4320,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
private static ReceiverValue getConstructorReceiver(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
CallableDescriptor constructor = resolvedCall.getResultingDescriptor();
|
||||
if (constructor.getExtensionReceiverParameter() != null) {
|
||||
// see comment on `withDispatchReceiver` parameter in
|
||||
// org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl.Companion.createIfAvailable
|
||||
assert constructor instanceof TypeAliasConstructorDescriptor :
|
||||
"Only type alias constructor can have an extension receiver: " + constructor;
|
||||
return resolvedCall.getExtensionReceiver();
|
||||
|
||||
@@ -48,7 +48,6 @@ import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingVisitorDispatcher;
|
||||
@@ -452,17 +451,18 @@ public class CallResolver {
|
||||
}
|
||||
|
||||
// If any constructor has type parameter (currently it only can be true for ones from Java), try to infer arguments for them
|
||||
// Otherwise use NO_EXPECTED_TYPE and knownTypeParametersSubstitutor
|
||||
// Otherwise use NO_EXPECTED_TYPE and known type substitutor
|
||||
boolean anyConstructorHasDeclaredTypeParameters =
|
||||
anyConstructorHasDeclaredTypeParameters(superType.getConstructor().getDeclarationDescriptor());
|
||||
|
||||
TypeSubstitutor knownTypeParametersSubstitutor = anyConstructorHasDeclaredTypeParameters ? null : TypeSubstitutor.create(superType);
|
||||
if (anyConstructorHasDeclaredTypeParameters) {
|
||||
context = context.replaceExpectedType(superType);
|
||||
}
|
||||
|
||||
Collection<ResolutionCandidate<ConstructorDescriptor>> candidates =
|
||||
CallResolverUtilKt.createResolutionCandidatesForConstructors(context.scope, context.call, superType, knownTypeParametersSubstitutor);
|
||||
CallResolverUtilKt.createResolutionCandidatesForConstructors(
|
||||
context.scope, context.call, superType, !anyConstructorHasDeclaredTypeParameters
|
||||
);
|
||||
|
||||
return new Pair<Collection<ResolutionCandidate<ConstructorDescriptor>>, BasicCallResolutionContext>(candidates, context);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -34,6 +33,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.getNestedTypeVariables
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.getTypeAliasConstructors
|
||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
@@ -194,18 +194,25 @@ fun createResolutionCandidatesForConstructors(
|
||||
lexicalScope: LexicalScope,
|
||||
call: Call,
|
||||
typeWithConstructors: KotlinType,
|
||||
knownSubstitutor: TypeSubstitutor? = null
|
||||
useKnownTypeSubstitutor: Boolean
|
||||
): Collection<ResolutionCandidate<ConstructorDescriptor>> {
|
||||
val classWithConstructors = typeWithConstructors.constructor.declarationDescriptor as ClassDescriptor
|
||||
|
||||
val unwrappedType = typeWithConstructors.unwrap()
|
||||
val knownSubstitutor =
|
||||
if (useKnownTypeSubstitutor)
|
||||
TypeSubstitutor.create(
|
||||
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
|
||||
)
|
||||
else null
|
||||
|
||||
val typeAliasDescriptor =
|
||||
if (unwrappedType is AbbreviatedType)
|
||||
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
|
||||
else
|
||||
null
|
||||
|
||||
val constructors = classWithConstructors.constructors
|
||||
val constructors = typeAliasDescriptor?.getTypeAliasConstructors(withDispatchReceiver = true) ?: classWithConstructors.constructors
|
||||
|
||||
if (constructors.isEmpty()) return emptyList()
|
||||
|
||||
@@ -229,22 +236,10 @@ fun createResolutionCandidatesForConstructors(
|
||||
}
|
||||
|
||||
return constructors.map {
|
||||
val constructorDescriptor = it.getConstructorDescriptorForResolution(knownSubstitutor, typeAliasDescriptor)
|
||||
ResolutionCandidate.create(call, constructorDescriptor, dispatchReceiver, receiverKind, knownSubstitutor)
|
||||
ResolutionCandidate.create(call, it, dispatchReceiver, receiverKind, knownSubstitutor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassConstructorDescriptor.getConstructorDescriptorForResolution(
|
||||
knownSubstitutor: TypeSubstitutor?,
|
||||
typeAliasDescriptor: TypeAliasDescriptor?
|
||||
): ConstructorDescriptor =
|
||||
if (typeAliasDescriptor != null)
|
||||
TypeAliasConstructorDescriptorImpl.createIfAvailable(typeAliasDescriptor, this, knownSubstitutor ?: TypeSubstitutor.EMPTY,
|
||||
withDispatchReceiver = true)
|
||||
?: throw AssertionError("Failed to create type alias constructor with substitutor: $knownSubstitutor")
|
||||
else
|
||||
this
|
||||
|
||||
fun KtLambdaExpression.getCorrespondingParameterForFunctionArgument(
|
||||
bindingContext: BindingContext
|
||||
): ValueParameterDescriptor? {
|
||||
|
||||
@@ -36,7 +36,9 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastI
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
|
||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectVariables
|
||||
import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.types.typeUtil.getImmediateSuperclassNotAny
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
@@ -319,22 +321,11 @@ private fun getClassWithConstructors(classifier: ClassifierDescriptor?): ClassDe
|
||||
private val ClassDescriptor.canHaveCallableConstructors: Boolean
|
||||
get() = !ErrorUtils.isError(this) && !kind.isSingleton
|
||||
|
||||
fun TypeAliasDescriptor.getTypeAliasConstructors(): Collection<TypeAliasConstructorDescriptor> {
|
||||
fun TypeAliasDescriptor.getTypeAliasConstructors(withDispatchReceiver: Boolean = false): Collection<TypeAliasConstructorDescriptor> {
|
||||
val classDescriptor = this.classDescriptor ?: return emptyList()
|
||||
if (!classDescriptor.canHaveCallableConstructors) return emptyList()
|
||||
|
||||
val substitutor = this.getTypeSubstitutorForUnderlyingClass() ?:
|
||||
throw AssertionError("classDescriptor should be non-null for $this")
|
||||
|
||||
return classDescriptor.constructors.mapNotNull {
|
||||
TypeAliasConstructorDescriptorImpl.createIfAvailable(this, it, substitutor)
|
||||
TypeAliasConstructorDescriptorImpl.createIfAvailable(this, it, withDispatchReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TypeAliasDescriptor.getTypeSubstitutorForUnderlyingClass(): TypeSubstitutor? {
|
||||
if (classDescriptor == null) return null
|
||||
|
||||
val expandedTypeParameters = expandedType.constructor.parameters
|
||||
val expandedTypeArguments = expandedType.arguments
|
||||
return TypeSubstitutor.create(IndexedParametersSubstitution(expandedTypeParameters, expandedTypeArguments))
|
||||
}
|
||||
|
||||
Vendored
+6
-6
@@ -21,19 +21,19 @@ class Generic<T1> {
|
||||
open inner class Generic<T2>
|
||||
|
||||
inner class Test1 : GI<T1>()
|
||||
inner class Test2 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GIInt<!>()
|
||||
inner class Test2 : <!TYPE_MISMATCH!>GIInt<!>()
|
||||
inner class Test3 : GIStar()
|
||||
inner class Test3a : test.Generic<*>.Inner()
|
||||
|
||||
inner class Test4<T2> : GG<T1, T2>()
|
||||
inner class Test5 : GG<T1, Int>()
|
||||
inner class Test6 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GG<!><Int, T1>()
|
||||
inner class Test7 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GG<!><Int, Int>()
|
||||
inner class Test8 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GIntG<!><Int>()
|
||||
inner class Test9 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GGInt<!><Int>()
|
||||
inner class Test6 : <!TYPE_MISMATCH!>GG<!><Int, T1>()
|
||||
inner class Test7 : <!TYPE_MISMATCH!>GG<!><Int, Int>()
|
||||
inner class Test8 : <!TYPE_MISMATCH!>GIntG<!><Int>()
|
||||
inner class Test9 : <!TYPE_MISMATCH!>GGInt<!><Int>()
|
||||
inner class Test10 : GGInt<T1>()
|
||||
|
||||
inner class Test11 : GG<T1, Int> {
|
||||
constructor() : super()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -13,4 +13,4 @@ class Test4 : CStar {
|
||||
constructor() : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>super<!>()
|
||||
}
|
||||
|
||||
class Test5 : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>CT<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>()<!>
|
||||
class Test5 : CT<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>()
|
||||
|
||||
+19
-7
@@ -106,22 +106,34 @@ class TypeAliasConstructorDescriptorImpl private constructor(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun TypeAliasDescriptor.getTypeSubstitutorForUnderlyingClass(): TypeSubstitutor? {
|
||||
if (classDescriptor == null) return null
|
||||
return TypeSubstitutor.create(expandedType)
|
||||
}
|
||||
|
||||
fun createIfAvailable(
|
||||
typeAliasDescriptor: TypeAliasDescriptor,
|
||||
constructor: ClassConstructorDescriptor,
|
||||
substitutor: TypeSubstitutor,
|
||||
withDispatchReceiver: Boolean = false
|
||||
// When resolution is ran for common calls, type aliases constructors are resolved as extensions
|
||||
// (i.e. after members, and with extension receiver)
|
||||
// But when resolving super-calls (with known set of candidates) constructors of inner classes are expected to have
|
||||
// an dispatch receiver
|
||||
withDispatchReceiver: Boolean
|
||||
): TypeAliasConstructorDescriptor? {
|
||||
val substitutorForUnderlyingClass = typeAliasDescriptor.getTypeSubstitutorForUnderlyingClass() ?: return null
|
||||
|
||||
val typeAliasConstructor =
|
||||
TypeAliasConstructorDescriptorImpl(typeAliasDescriptor, constructor, null, constructor.annotations,
|
||||
constructor.kind, typeAliasDescriptor.source)
|
||||
|
||||
val valueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(typeAliasConstructor, constructor.valueParameters, substitutor, false, false)
|
||||
?: return null
|
||||
val valueParameters =
|
||||
FunctionDescriptorImpl.getSubstitutedValueParameters(
|
||||
typeAliasConstructor, constructor.valueParameters, substitutorForUnderlyingClass, false, false
|
||||
)
|
||||
?: return null
|
||||
|
||||
val returnType = run {
|
||||
val returnTypeNoAbbreviation = substitutor.substitute(constructor.returnType, Variance.INVARIANT)
|
||||
val returnTypeNoAbbreviation = substitutorForUnderlyingClass.substitute(constructor.returnType, Variance.INVARIANT)
|
||||
?: return null
|
||||
val abbreviation = typeAliasDescriptor.defaultType
|
||||
if (returnTypeNoAbbreviation is SimpleType && abbreviation is SimpleType)
|
||||
@@ -132,10 +144,10 @@ class TypeAliasConstructorDescriptorImpl private constructor(
|
||||
|
||||
val receiverParameterType =
|
||||
if (withDispatchReceiver) null
|
||||
else constructor.dispatchReceiverParameter?.let { substitutor.safeSubstitute(it.type, Variance.INVARIANT) }
|
||||
else constructor.dispatchReceiverParameter?.let { substitutorForUnderlyingClass.safeSubstitute(it.type, Variance.INVARIANT) }
|
||||
|
||||
val dispatchReceiver =
|
||||
if (withDispatchReceiver) constructor.dispatchReceiverParameter?.substitute(substitutor)
|
||||
if (withDispatchReceiver) constructor.dispatchReceiverParameter?.substitute(substitutorForUnderlyingClass)
|
||||
else null
|
||||
|
||||
typeAliasConstructor.initialize(
|
||||
|
||||
Reference in New Issue
Block a user