Substitute underlying constructor when substituting type alias constructor

KT-17426 Constructor call of typealiased class gets suspicious type arguemnts
This commit is contained in:
Dmitry Petrov
2017-04-19 19:25:27 +03:00
parent 02fec6e4a5
commit a3985bbdd3
5 changed files with 88 additions and 28 deletions
@@ -34,7 +34,7 @@ interface TypeAliasConstructorDescriptor : ConstructorDescriptor {
override fun getOriginal(): TypeAliasConstructorDescriptor
override fun substitute(substitutor: TypeSubstitutor): TypeAliasConstructorDescriptor
override fun substitute(substitutor: TypeSubstitutor): TypeAliasConstructorDescriptor?
val withDispatchReceiver: TypeAliasConstructorDescriptor?
@@ -50,7 +50,7 @@ interface TypeAliasConstructorDescriptor : ConstructorDescriptor {
class TypeAliasConstructorDescriptorImpl private constructor(
val storageManager: StorageManager,
override val typeAliasDescriptor: TypeAliasDescriptor,
override val underlyingConstructorDescriptor: ClassConstructorDescriptor,
underlyingConstructorDescriptor: ClassConstructorDescriptor,
original: TypeAliasConstructorDescriptor?,
annotations: Annotations,
kind: Kind,
@@ -58,32 +58,38 @@ class TypeAliasConstructorDescriptorImpl private constructor(
) : TypeAliasConstructorDescriptor,
FunctionDescriptorImpl(typeAliasDescriptor, original, annotations, Name.special("<init>"), kind, source)
{
// 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
// a dispatch receiver
override val withDispatchReceiver: TypeAliasConstructorDescriptor? by storageManager.createNullableLazyValue {
val typeAliasConstructor = TypeAliasConstructorDescriptorImpl(storageManager,
typeAliasDescriptor,
underlyingConstructorDescriptor,
this,
underlyingConstructorDescriptor.annotations,
underlyingConstructorDescriptor.kind,
typeAliasDescriptor.source)
val substitutorForUnderlyingClass = typeAliasDescriptor.getTypeSubstitutorForUnderlyingClass() ?: return@createNullableLazyValue null
TypeAliasConstructorDescriptorImpl(
storageManager,
typeAliasDescriptor,
underlyingConstructorDescriptor,
this,
underlyingConstructorDescriptor.annotations,
underlyingConstructorDescriptor.kind,
typeAliasDescriptor.source
).also { typeAliasConstructor ->
val substitutorForUnderlyingClass = typeAliasDescriptor.getTypeSubstitutorForUnderlyingClass() ?:
return@createNullableLazyValue null
typeAliasConstructor.initialize(null,
underlyingConstructorDescriptor.dispatchReceiverParameter?.substitute(substitutorForUnderlyingClass),
typeAliasDescriptor.declaredTypeParameters,
valueParameters,
returnType,
Modality.FINAL,
typeAliasDescriptor.visibility)
return@createNullableLazyValue typeAliasConstructor
typeAliasConstructor.initialize(
null,
underlyingConstructorDescriptor.dispatchReceiverParameter?.substitute(substitutorForUnderlyingClass),
typeAliasDescriptor.declaredTypeParameters,
valueParameters,
returnType,
Modality.FINAL,
typeAliasDescriptor.visibility
)
}
}
override var underlyingConstructorDescriptor: ClassConstructorDescriptor = underlyingConstructorDescriptor
private set
override fun isPrimary(): Boolean =
underlyingConstructorDescriptor.isPrimary
@@ -99,8 +105,23 @@ class TypeAliasConstructorDescriptorImpl private constructor(
override fun getOriginal(): TypeAliasConstructorDescriptor =
super.getOriginal() as TypeAliasConstructorDescriptor
override fun substitute(substitutor: TypeSubstitutor): TypeAliasConstructorDescriptor =
super.substitute(substitutor) as TypeAliasConstructorDescriptor
override fun substitute(substitutor: TypeSubstitutor): TypeAliasConstructorDescriptor? {
// class C<T>(val x: T)
// typealias A<Q> = C<List<Q>>
//
// val test = A(listOf(42))
//
// Here return type for substituted type alias constructor is 'C<List<Int>>',
// which yields us a substitution [T -> List<Int>] that should be applied to
// the unsubstituted underlying constructor with signature '<T> (T) -> C<T>'
// producing substituted underlying constructor with signature '(List<Int>) -> C<List<Int>>'.
val substitutedTypeAliasConstructor = super.substitute(substitutor) as TypeAliasConstructorDescriptorImpl
val underlyingConstructorSubstitutor = TypeSubstitutor.create(substitutedTypeAliasConstructor.returnType)
val substitutedUnderlyingConstructor = underlyingConstructorDescriptor.original.substitute(underlyingConstructorSubstitutor)
?: return null
substitutedTypeAliasConstructor.underlyingConstructorDescriptor = substitutedUnderlyingConstructor
return substitutedTypeAliasConstructor
}
override fun copy(
newOwner: DeclarationDescriptor,