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:
Denis Zharkov
2017-03-02 13:10:10 +03:00
parent 2b21280ba9
commit be90f7d331
7 changed files with 48 additions and 48 deletions
@@ -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))
}
@@ -21,19 +21,19 @@ 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> {
constructor() : super() constructor() : super()
} }
} }
@@ -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!>*<!>>()
@@ -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(