diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 49d351a61c5..abde93d3c26 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -4320,6 +4320,8 @@ public class ExpressionCodegen extends KtVisitor 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(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java index 86372c7489b..c9009b4f312 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -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> candidates = - CallResolverUtilKt.createResolutionCandidatesForConstructors(context.scope, context.call, superType, knownTypeParametersSubstitutor); + CallResolverUtilKt.createResolutionCandidatesForConstructors( + context.scope, context.call, superType, !anyConstructorHasDeclaredTypeParameters + ); return new Pair>, BasicCallResolutionContext>(candidates, context); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt index d24c77e8806..aebbb5b3aa6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolverUtil.kt @@ -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> { 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? { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index 2e473f5e9ee..05e5bd08fa0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -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 { +fun TypeAliasDescriptor.getTypeAliasConstructors(withDispatchReceiver: Boolean = false): Collection { 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)) -} diff --git a/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.kt b/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.kt index 6db8f0d767d..39464555cfd 100644 --- a/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.kt +++ b/compiler/testData/diagnostics/tests/typealias/innerClassTypeAliasConstructorInSupertypes.kt @@ -21,19 +21,19 @@ class Generic { open inner class Generic inner class Test1 : GI() - inner class Test2 : GIInt() + inner class Test2 : GIInt() inner class Test3 : GIStar() inner class Test3a : test.Generic<*>.Inner() inner class Test4 : GG() inner class Test5 : GG() - inner class Test6 : GG() - inner class Test7 : GG() - inner class Test8 : GIntG() - inner class Test9 : GGInt() + inner class Test6 : GG() + inner class Test7 : GG() + inner class Test8 : GIntG() + inner class Test9 : GGInt() inner class Test10 : GGInt() inner class Test11 : GG { constructor() : super() } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt index 079dda3d220..b6389e8c9dd 100644 --- a/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt +++ b/compiler/testData/diagnostics/tests/typealias/typeAliasConstructorForProjectionInSupertypes.kt @@ -13,4 +13,4 @@ class Test4 : CStar { constructor() : super() } -class Test5 : CT<*>() \ No newline at end of file +class Test5 : CT<*>() 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 32d14701c8c..1f81a339127 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeAliasConstructorDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/TypeAliasConstructorDescriptor.kt @@ -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(