From eb5904ea8e1ccb87cb0bddd3f7b3ca409e258ada Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 16 Mar 2018 17:11:24 +0300 Subject: [PATCH] Underlying constructor for type alias should always be substituted Otherwise PSI2IR fails because of type mismatch. --- .../codegen/state/KotlinTypeMapper.java | 2 +- .../jetbrains/kotlin/ir/util/SymbolTable.kt | 3 +- .../specializedTypeAliasConstructorCall.kt | 5 +++ .../specializedTypeAliasConstructorCall.txt | 43 +++++++++++++++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 6 +++ .../impl/FunctionDescriptorImpl.java | 10 +++++ .../impl/TypeAliasConstructorDescriptor.kt | 19 ++++---- .../kotlin/types/DescriptorSubstitutor.java | 8 ++-- 8 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.kt create mode 100644 compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 64f0660a8be..eec53c20271 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -1117,7 +1117,7 @@ public class KotlinTypeMapper { } if (f instanceof TypeAliasConstructorDescriptor) { - return mapSignature(((TypeAliasConstructorDescriptor) f).getUnderlyingConstructorDescriptor(), kind, skipGenericSignature); + return mapSignature(((TypeAliasConstructorDescriptor) f).getUnderlyingConstructorDescriptor().getOriginal(), kind, skipGenericSignature); } if (f instanceof FunctionImportedFromObject) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index 27ca8bfb73a..66c1d3500a3 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -100,7 +100,8 @@ class SymbolTable { private var currentScope: Scope? = null override fun get(d: D): S? { - val scope = currentScope ?: throw AssertionError("No active scope") + val scope = currentScope + ?: throw AssertionError("No active scope") return scope[d] } diff --git a/compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.kt b/compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.kt new file mode 100644 index 00000000000..8a7f4bdff7d --- /dev/null +++ b/compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.kt @@ -0,0 +1,5 @@ +class Cell(val value: T) + +typealias IntAlias = Cell + +fun test() = IntAlias(42) \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.txt b/compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.txt new file mode 100644 index 00000000000..6d3c028bfe1 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.txt @@ -0,0 +1,43 @@ +FILE fqName: fileName:/specializedTypeAliasConstructorCall.kt + CLASS CLASS name:Cell modality:FINAL visibility:public flags: + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:Cell flags: + superClasses: + CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Any modality:OPEN visibility:public flags: + TYPE_PARAMETER name:T index:0 variance: upperBounds:[kotlin.Any?] + superClassifiers: + CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Any modality:OPEN visibility:public flags: + CONSTRUCTOR visibility:public <> (value:T) returnType:Cell flags: + VALUE_PARAMETER name:value index:0 type:T flags: + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' + INSTANCE_INITIALIZER_CALL classDescriptor='Cell' + PROPERTY name:value type:T visibility:public modality:FINAL flags:val + FIELD PROPERTY_BACKING_FIELD name:value type:T visibility:public + EXPRESSION_BODY + GET_VAR 'value-parameter value: T' type=T origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> ($this:Cell) returnType:T flags: + $this: VALUE_PARAMETER name: type:Cell flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): T' + GET_FIELD 'value: T' type=T origin=null + receiver: GET_VAR 'this@Cell: Cell' type=Cell origin=null + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:Boolean flags: + overridden: + FUN IR_EXTERNAL_DECLARATION_STUB name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:Boolean flags: + $this: VALUE_PARAMETER name: type:kotlin.Any flags: + VALUE_PARAMETER name:other index:0 type:kotlin.Any? flags: + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:Int flags: + overridden: + FUN IR_EXTERNAL_DECLARATION_STUB name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:Int flags: + $this: VALUE_PARAMETER name: type:kotlin.Any flags: + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:String flags: + overridden: + FUN IR_EXTERNAL_DECLARATION_STUB name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:String flags: + $this: VALUE_PARAMETER name: type:kotlin.Any flags: + TYPEALIAS typealias IntAlias = Cell type=Cell + FUN name:test visibility:public modality:FINAL <> () returnType:Cell flags: + BLOCK_BODY + RETURN type=kotlin.Nothing from='test(): IntAlias /* = Cell */' + CALL 'constructor Cell(Int)' type=Cell origin=null + : null + value: CONST Int type=kotlin.Int value=42 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 8d6f711020f..09f2130d57a 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -951,6 +951,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("specializedTypeAliasConstructorCall.kt") + public void testSpecializedTypeAliasConstructorCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/specializedTypeAliasConstructorCall.kt"); + doTest(fileName); + } + @TestMetadata("stringComparisons.kt") public void testStringComparisons() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/stringComparisons.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java index 89bf61c05a4..6ba1d21e510 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java @@ -599,6 +599,7 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo final TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters( unsubstitutedTypeParameters, configuration.substitution, substitutedDescriptor, substitutedTypeParameters, wereChanges ); + if (substitutor == null) return null; KotlinType substitutedReceiverParameterType = null; if (configuration.newExtensionReceiverParameterType != null) { @@ -768,6 +769,15 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo return visitor.visitFunctionDescriptor(this, data); } + @Nullable + public static List getSubstitutedValueParameters( + FunctionDescriptor substitutedDescriptor, + @NotNull List unsubstitutedValueParameters, + @NotNull TypeSubstitutor substitutor + ) { + return getSubstitutedValueParameters(substitutedDescriptor, unsubstitutedValueParameters, substitutor, false, false, null); + } + @Nullable public static List getSubstitutedValueParameters( FunctionDescriptor substitutedDescriptor, diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeAliasConstructorDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeAliasConstructorDescriptor.kt index 8113e78be41..d3d3331beed 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeAliasConstructorDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeAliasConstructorDescriptor.kt @@ -175,27 +175,26 @@ class TypeAliasConstructorDescriptorImpl private constructor( constructor: ClassConstructorDescriptor ): TypeAliasConstructorDescriptor? { val substitutorForUnderlyingClass = typeAliasDescriptor.getTypeSubstitutorForUnderlyingClass() ?: return null + val substitutedConstructor = constructor.substitute(substitutorForUnderlyingClass) ?: return null val typeAliasConstructor = TypeAliasConstructorDescriptorImpl( - storageManager, typeAliasDescriptor, constructor, null, constructor.annotations, + storageManager, typeAliasDescriptor, + substitutedConstructor, + null, constructor.annotations, constructor.kind, typeAliasDescriptor.source ) val valueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters( - typeAliasConstructor, constructor.valueParameters, substitutorForUnderlyingClass, false, false, - null + typeAliasConstructor, constructor.valueParameters, substitutorForUnderlyingClass ) ?: return null - val returnType = run { - val returnTypeNoAbbreviation = substitutorForUnderlyingClass.substitute(constructor.returnType, Variance.INVARIANT) - ?: return null - returnTypeNoAbbreviation.unwrap().lowerIfFlexible().withAbbreviation(typeAliasDescriptor.defaultType) - } + val returnType = substitutedConstructor.returnType.unwrap().lowerIfFlexible().withAbbreviation(typeAliasDescriptor.defaultType) - val receiverParameterType = - constructor.dispatchReceiverParameter?.let { substitutorForUnderlyingClass.safeSubstitute(it.type, Variance.INVARIANT) } + val receiverParameterType = constructor.dispatchReceiverParameter?.let { + substitutorForUnderlyingClass.safeSubstitute(it.type, Variance.INVARIANT) + } typeAliasConstructor.initialize( receiverParameterType, diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java index 2d8940785b1..008a763b1f6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/DescriptorSubstitutor.java @@ -40,10 +40,12 @@ public class DescriptorSubstitutor { @NotNull DeclarationDescriptor newContainingDeclaration, @NotNull @Mutable List result ) { - return substituteTypeParameters(typeParameters, originalSubstitution, newContainingDeclaration, result, null); + TypeSubstitutor substitutor = substituteTypeParameters(typeParameters, originalSubstitution, newContainingDeclaration, result, null); + if (substitutor == null) throw new AssertionError("Substitution failed"); + return substitutor; } - @NotNull + @Nullable public static TypeSubstitutor substituteTypeParameters( @ReadOnly @NotNull List typeParameters, @NotNull TypeSubstitution originalSubstitution, @@ -80,7 +82,7 @@ public class DescriptorSubstitutor { TypeParameterDescriptorImpl substituted = substitutedMap.get(descriptor); for (KotlinType upperBound : descriptor.getUpperBounds()) { KotlinType substitutedBound = substitutor.substitute(upperBound, Variance.IN_VARIANCE); - assert substitutedBound != null : "Upper bound failed to substitute: " + descriptor; + if (substitutedBound == null) return null; if (substitutedBound != upperBound && wereChanges != null) { wereChanges[0] = true;