Skip to content

Commit

Permalink
Substitute underlying constructor when substituting type alias constr…
Browse files Browse the repository at this point in the history
…uctor

KT-17426 Constructor call of typealiased class gets suspicious type arguemnts
  • Loading branch information
dnpetrov committed Apr 20, 2017
1 parent 02fec6e commit a3985bb
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ FILE /delegatingConstructorCallToTypeAliasConstructor.kt
CLASS CLASS C1
CONSTRUCTOR public constructor C1()
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'constructor Cell(T)'
value: TYPE_OP type=T origin=IMPLICIT_CAST typeOperand=T
CONST String type=kotlin.String value='O'
DELEGATING_CONSTRUCTOR_CALL 'constructor Cell(String)'
value: CONST String type=kotlin.String value='O'
INSTANCE_INITIALIZER_CALL classDescriptor='C1'
CLASS CLASS C2
CONSTRUCTOR public constructor C2()
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'constructor Cell(T)'
value: TYPE_OP type=T origin=IMPLICIT_CAST typeOperand=T
CONST String type=kotlin.String value='K'
DELEGATING_CONSTRUCTOR_CALL 'constructor Cell(String)'
value: CONST String type=kotlin.String value='K'
INSTANCE_INITIALIZER_CALL classDescriptor='C2'
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class A<Q>(val q: Q)

typealias B<X> = A<X>

typealias B2<T> = A<A<T>>

fun bar() {
val b = B(2)
val b2 = B2(b)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FILE /typeAliasCtorForGenericClass.kt
CLASS CLASS A
CONSTRUCTOR public constructor A<Q>(q: Q)
BLOCK_BODY
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
INSTANCE_INITIALIZER_CALL classDescriptor='A'
PROPERTY public final val q: Q
FIELD PROPERTY_BACKING_FIELD public final val q: Q
EXPRESSION_BODY
GET_VAR 'value-parameter q: Q' type=Q origin=INITIALIZE_PROPERTY_FROM_PARAMETER
FUN DEFAULT_PROPERTY_ACCESSOR public final fun <get-q>(): Q
BLOCK_BODY
RETURN type=kotlin.Nothing from='<get-q>(): Q'
GET_FIELD 'q: Q' type=Q origin=null
receiver: GET_VAR '<receiver: A>' type=A<Q> origin=null
TYPEALIAS typealias B = A<X> type=A<X>
TYPEALIAS typealias B2 = A<A<T>> type=A<A<T>>
FUN public fun bar(): kotlin.Unit
BLOCK_BODY
VAR val b: B<kotlin.Int> /* = A<kotlin.Int> */
CALL 'constructor A(Int)' type=A<kotlin.Int> origin=null
q: CONST Int type=kotlin.Int value='2'
VAR val b2: B2<kotlin.Int> /* = A<A<kotlin.Int>> */
CALL 'constructor A(A<Int>)' type=A<A<kotlin.Int>> origin=null
q: GET_VAR 'b: B<Int> /* = A<Int> */' type=B<kotlin.Int> /* = A<kotlin.Int> */ origin=null
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,12 @@ public void testIntegerCoercionToT() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/regressions/integerCoercionToT.kt");
doTest(fileName);
}

@TestMetadata("typeAliasCtorForGenericClass.kt")
public void testTypeAliasCtorForGenericClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/regressions/typeAliasCtorForGenericClass.kt");
doTest(fileName);
}
}

@TestMetadata("compiler/testData/ir/irText/singletons")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand All @@ -50,40 +50,46 @@ 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,
source: SourceElement
) : 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

typeAliasConstructor.initialize(null,
underlyingConstructorDescriptor.dispatchReceiverParameter?.substitute(substitutorForUnderlyingClass),
typeAliasDescriptor.declaredTypeParameters,
valueParameters,
returnType,
Modality.FINAL,
typeAliasDescriptor.visibility)

return@createNullableLazyValue typeAliasConstructor
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
)
}
}

override var underlyingConstructorDescriptor: ClassConstructorDescriptor = underlyingConstructorDescriptor
private set

override fun isPrimary(): Boolean =
underlyingConstructorDescriptor.isPrimary

Expand All @@ -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,
Expand Down

0 comments on commit a3985bb

Please sign in to comment.