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) {
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))
}
@@ -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()
}
}
}
@@ -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!>*<!>>()
@@ -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(