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) {
|
private static ReceiverValue getConstructorReceiver(@NotNull ResolvedCall<?> resolvedCall) {
|
||||||
CallableDescriptor constructor = resolvedCall.getResultingDescriptor();
|
CallableDescriptor constructor = resolvedCall.getResultingDescriptor();
|
||||||
if (constructor.getExtensionReceiverParameter() != null) {
|
if (constructor.getExtensionReceiverParameter() != null) {
|
||||||
|
// see comment on `withDispatchReceiver` parameter in
|
||||||
|
// org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl.Companion.createIfAvailable
|
||||||
assert constructor instanceof TypeAliasConstructorDescriptor :
|
assert constructor instanceof TypeAliasConstructorDescriptor :
|
||||||
"Only type alias constructor can have an extension receiver: " + constructor;
|
"Only type alias constructor can have an extension receiver: " + constructor;
|
||||||
return resolvedCall.getExtensionReceiver();
|
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.LexicalScope;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
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.ExpressionTypingContext;
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
|
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
|
||||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingVisitorDispatcher;
|
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
|
// 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 =
|
boolean anyConstructorHasDeclaredTypeParameters =
|
||||||
anyConstructorHasDeclaredTypeParameters(superType.getConstructor().getDeclarationDescriptor());
|
anyConstructorHasDeclaredTypeParameters(superType.getConstructor().getDeclarationDescriptor());
|
||||||
|
|
||||||
TypeSubstitutor knownTypeParametersSubstitutor = anyConstructorHasDeclaredTypeParameters ? null : TypeSubstitutor.create(superType);
|
|
||||||
if (anyConstructorHasDeclaredTypeParameters) {
|
if (anyConstructorHasDeclaredTypeParameters) {
|
||||||
context = context.replaceExpectedType(superType);
|
context = context.replaceExpectedType(superType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<ResolutionCandidate<ConstructorDescriptor>> candidates =
|
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);
|
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.ReflectionTypes
|
||||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptorImpl
|
|
||||||
import org.jetbrains.kotlin.lexer.KtToken
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.model.ArgumentMatch
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate
|
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.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
@@ -194,18 +194,25 @@ fun createResolutionCandidatesForConstructors(
|
|||||||
lexicalScope: LexicalScope,
|
lexicalScope: LexicalScope,
|
||||||
call: Call,
|
call: Call,
|
||||||
typeWithConstructors: KotlinType,
|
typeWithConstructors: KotlinType,
|
||||||
knownSubstitutor: TypeSubstitutor? = null
|
useKnownTypeSubstitutor: Boolean
|
||||||
): Collection<ResolutionCandidate<ConstructorDescriptor>> {
|
): Collection<ResolutionCandidate<ConstructorDescriptor>> {
|
||||||
val classWithConstructors = typeWithConstructors.constructor.declarationDescriptor as ClassDescriptor
|
val classWithConstructors = typeWithConstructors.constructor.declarationDescriptor as ClassDescriptor
|
||||||
|
|
||||||
val unwrappedType = typeWithConstructors.unwrap()
|
val unwrappedType = typeWithConstructors.unwrap()
|
||||||
|
val knownSubstitutor =
|
||||||
|
if (useKnownTypeSubstitutor)
|
||||||
|
TypeSubstitutor.create(
|
||||||
|
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
|
||||||
|
)
|
||||||
|
else null
|
||||||
|
|
||||||
val typeAliasDescriptor =
|
val typeAliasDescriptor =
|
||||||
if (unwrappedType is AbbreviatedType)
|
if (unwrappedType is AbbreviatedType)
|
||||||
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
|
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
|
|
||||||
val constructors = classWithConstructors.constructors
|
val constructors = typeAliasDescriptor?.getTypeAliasConstructors(withDispatchReceiver = true) ?: classWithConstructors.constructors
|
||||||
|
|
||||||
if (constructors.isEmpty()) return emptyList()
|
if (constructors.isEmpty()) return emptyList()
|
||||||
|
|
||||||
@@ -229,22 +236,10 @@ fun createResolutionCandidatesForConstructors(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return constructors.map {
|
return constructors.map {
|
||||||
val constructorDescriptor = it.getConstructorDescriptorForResolution(knownSubstitutor, typeAliasDescriptor)
|
ResolutionCandidate.create(call, it, dispatchReceiver, receiverKind, knownSubstitutor)
|
||||||
ResolutionCandidate.create(call, constructorDescriptor, 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(
|
fun KtLambdaExpression.getCorrespondingParameterForFunctionArgument(
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
): ValueParameterDescriptor? {
|
): 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.collectFunctions
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectVariables
|
import org.jetbrains.kotlin.resolve.scopes.utils.collectVariables
|
||||||
import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup
|
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.types.typeUtil.getImmediateSuperclassNotAny
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
@@ -319,22 +321,11 @@ private fun getClassWithConstructors(classifier: ClassifierDescriptor?): ClassDe
|
|||||||
private val ClassDescriptor.canHaveCallableConstructors: Boolean
|
private val ClassDescriptor.canHaveCallableConstructors: Boolean
|
||||||
get() = !ErrorUtils.isError(this) && !kind.isSingleton
|
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()
|
val classDescriptor = this.classDescriptor ?: return emptyList()
|
||||||
if (!classDescriptor.canHaveCallableConstructors) return emptyList()
|
if (!classDescriptor.canHaveCallableConstructors) return emptyList()
|
||||||
|
|
||||||
val substitutor = this.getTypeSubstitutorForUnderlyingClass() ?:
|
|
||||||
throw AssertionError("classDescriptor should be non-null for $this")
|
|
||||||
|
|
||||||
return classDescriptor.constructors.mapNotNull {
|
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
+5
-5
@@ -21,16 +21,16 @@ class Generic<T1> {
|
|||||||
open inner class Generic<T2>
|
open inner class Generic<T2>
|
||||||
|
|
||||||
inner class Test1 : GI<T1>()
|
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 Test3 : GIStar()
|
||||||
inner class Test3a : test.Generic<*>.Inner()
|
inner class Test3a : test.Generic<*>.Inner()
|
||||||
|
|
||||||
inner class Test4<T2> : GG<T1, T2>()
|
inner class Test4<T2> : GG<T1, T2>()
|
||||||
inner class Test5 : GG<T1, Int>()
|
inner class Test5 : GG<T1, Int>()
|
||||||
inner class Test6 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GG<!><Int, T1>()
|
inner class Test6 : <!TYPE_MISMATCH!>GG<!><Int, T1>()
|
||||||
inner class Test7 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GG<!><Int, Int>()
|
inner class Test7 : <!TYPE_MISMATCH!>GG<!><Int, Int>()
|
||||||
inner class Test8 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GIntG<!><Int>()
|
inner class Test8 : <!TYPE_MISMATCH!>GIntG<!><Int>()
|
||||||
inner class Test9 : <!UNRESOLVED_REFERENCE, DEBUG_INFO_UNRESOLVED_WITH_TARGET!>GGInt<!><Int>()
|
inner class Test9 : <!TYPE_MISMATCH!>GGInt<!><Int>()
|
||||||
inner class Test10 : GGInt<T1>()
|
inner class Test10 : GGInt<T1>()
|
||||||
|
|
||||||
inner class Test11 : GG<T1, Int> {
|
inner class Test11 : GG<T1, Int> {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -13,4 +13,4 @@ class Test4 : CStar {
|
|||||||
constructor() : <!EXPANDED_TYPE_CANNOT_BE_CONSTRUCTED!>super<!>()
|
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 {
|
companion object {
|
||||||
|
private fun TypeAliasDescriptor.getTypeSubstitutorForUnderlyingClass(): TypeSubstitutor? {
|
||||||
|
if (classDescriptor == null) return null
|
||||||
|
return TypeSubstitutor.create(expandedType)
|
||||||
|
}
|
||||||
|
|
||||||
fun createIfAvailable(
|
fun createIfAvailable(
|
||||||
typeAliasDescriptor: TypeAliasDescriptor,
|
typeAliasDescriptor: TypeAliasDescriptor,
|
||||||
constructor: ClassConstructorDescriptor,
|
constructor: ClassConstructorDescriptor,
|
||||||
substitutor: TypeSubstitutor,
|
// When resolution is ran for common calls, type aliases constructors are resolved as extensions
|
||||||
withDispatchReceiver: Boolean = false
|
// (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? {
|
): TypeAliasConstructorDescriptor? {
|
||||||
|
val substitutorForUnderlyingClass = typeAliasDescriptor.getTypeSubstitutorForUnderlyingClass() ?: return null
|
||||||
|
|
||||||
val typeAliasConstructor =
|
val typeAliasConstructor =
|
||||||
TypeAliasConstructorDescriptorImpl(typeAliasDescriptor, constructor, null, constructor.annotations,
|
TypeAliasConstructorDescriptorImpl(typeAliasDescriptor, constructor, null, constructor.annotations,
|
||||||
constructor.kind, typeAliasDescriptor.source)
|
constructor.kind, typeAliasDescriptor.source)
|
||||||
|
|
||||||
val valueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(typeAliasConstructor, constructor.valueParameters, substitutor, false, false)
|
val valueParameters =
|
||||||
?: return null
|
FunctionDescriptorImpl.getSubstitutedValueParameters(
|
||||||
|
typeAliasConstructor, constructor.valueParameters, substitutorForUnderlyingClass, false, false
|
||||||
|
)
|
||||||
|
?: return null
|
||||||
|
|
||||||
val returnType = run {
|
val returnType = run {
|
||||||
val returnTypeNoAbbreviation = substitutor.substitute(constructor.returnType, Variance.INVARIANT)
|
val returnTypeNoAbbreviation = substitutorForUnderlyingClass.substitute(constructor.returnType, Variance.INVARIANT)
|
||||||
?: return null
|
?: return null
|
||||||
val abbreviation = typeAliasDescriptor.defaultType
|
val abbreviation = typeAliasDescriptor.defaultType
|
||||||
if (returnTypeNoAbbreviation is SimpleType && abbreviation is SimpleType)
|
if (returnTypeNoAbbreviation is SimpleType && abbreviation is SimpleType)
|
||||||
@@ -132,10 +144,10 @@ class TypeAliasConstructorDescriptorImpl private constructor(
|
|||||||
|
|
||||||
val receiverParameterType =
|
val receiverParameterType =
|
||||||
if (withDispatchReceiver) null
|
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 =
|
val dispatchReceiver =
|
||||||
if (withDispatchReceiver) constructor.dispatchReceiverParameter?.substitute(substitutor)
|
if (withDispatchReceiver) constructor.dispatchReceiverParameter?.substitute(substitutorForUnderlyingClass)
|
||||||
else null
|
else null
|
||||||
|
|
||||||
typeAliasConstructor.initialize(
|
typeAliasConstructor.initialize(
|
||||||
|
|||||||
Reference in New Issue
Block a user