diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 184114c6969..49368c0278f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -1169,22 +1169,15 @@ public class DescriptorResolver { } public static void checkBoundsInTypeAlias( - @NotNull KtUserType typeAliasElement, + @NotNull TypeAliasExpansionReportStrategy reportStrategy, @NotNull KotlinType typeArgument, @NotNull TypeParameterDescriptor typeParameterDescriptor, - @NotNull TypeSubstitutor substitutor, - @NotNull BindingTrace trace + @NotNull TypeSubstitutor substitutor ) { - DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); - assert containingDeclaration instanceof ClassifierDescriptor : - "Containing declaration of a type parameter should be a classifier, got " + containingDeclaration; - ClassifierDescriptor containingClassifier = (ClassifierDescriptor) containingDeclaration; - for (KotlinType bound : typeParameterDescriptor.getUpperBounds()) { KotlinType substitutedBound = substitutor.safeSubstitute(bound, Variance.INVARIANT); if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(typeArgument, substitutedBound)) { - trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on( - typeAliasElement, substitutedBound, typeArgument, containingClassifier)); + reportStrategy.boundsViolationInSubstitution(substitutedBound, typeArgument, typeParameterDescriptor); } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt new file mode 100644 index 00000000000..d9db75850aa --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeAliasExpansionReportStrategy.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.types.KotlinType + +interface TypeAliasExpansionReportStrategy { + fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) + fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType) + fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) + fun boundsViolationInSubstitution(bound: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) + + object DEFAULT : TypeAliasExpansionReportStrategy { + override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {} + override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType) {} + override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) {} + override fun boundsViolationInSubstitution(bound: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {} + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index 1d52b22673b..5b2ec67ea19 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -428,9 +428,13 @@ class TypeResolver( // TODO appendDefaultArgumentsForInnerScope val typeAliasArguments = typeAliasQualifierPart.typeArguments?.arguments.orEmpty() + val reportStrategy = TracingTypeAliasExpansionReportStrategy( + c.trace, + type, typeAliasQualifierPart.typeArguments ?: typeAliasQualifierPart.expression, + typeAliasDescriptor, typeAliasDescriptor.declaredTypeParameters, typeAliasArguments) + if (typeAliasParameters.size != typeAliasArguments.size) { - c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeAliasQualifierPart.typeArguments ?: typeAliasQualifierPart.expression, - typeAliasParameters.size, typeAliasDescriptor)) + reportStrategy.wrongNumberOfTypeArguments(typeAliasDescriptor, typeAliasParameters.size) return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeAliasConstructor) } @@ -440,24 +444,56 @@ class TypeResolver( type(abbreviatedType) } else { - val typeAliasExpansion = createTypeAliasExpansionFromSource(c, type, typeAliasDescriptor, typeAliasArguments) - val expandedType = expandTypeAlias(c, typeAliasExpansion, annotations) + val arguments = resolveTypeProjections(c, typeAliasDescriptor.typeConstructor, typeAliasArguments) + val typeAliasExpansion = createTypeAliasExpansion(null, typeAliasDescriptor, arguments) + val expandedType = expandTypeAlias(c, typeAliasExpansion, reportStrategy, annotations, 0) type(expandedType) } } + private class TracingTypeAliasExpansionReportStrategy( + val trace: BindingTrace, + val type: KtUserType, + val typeArgumentsOrTypeName: KtElement, + val typeAliasDescriptor: TypeAliasDescriptor, + val typeParameters: List, + val typeArguments: List + ) : TypeAliasExpansionReportStrategy { + private val mappedArguments = typeParameters.zip(typeArguments).toMap() + + override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) { + trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentsOrTypeName, numberOfParameters, typeAliasDescriptor)) + } + + override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType) { + val argumentElement = typeParameter?.let { mappedArguments[it] } + if (argumentElement != null && typeParameter != null) { + trace.report(CONFLICTING_PROJECTION.on(argumentElement, typeParameter)) + } + else { + trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on(type, typeAliasDescriptor.underlyingType)) + } + } + + override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) { + trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(type, typeAlias)) + } + + override fun boundsViolationInSubstitution(bound: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) { + TODO() + } + } + private class AbbreviatedTypeImpl(override val abbreviatedType: KotlinType): AbbreviatedType - private fun withAbbreviatedType(abbreviatedType: KotlinType): TypeCapabilities = - SingletonTypeCapabilities(AbbreviatedType::class.java, AbbreviatedTypeImpl(abbreviatedType)) - - private class TypeAliasExpansionContext( - val element: KtUserType, - val argumentElements: Map - ) + private fun KotlinType.withAbbreviatedType(abbreviatedType: KotlinType): KotlinType = + if (isError) + this + else + replace(newCapabilities = capabilities.overrideCapability(AbbreviatedType::class.java, + AbbreviatedTypeImpl(abbreviatedType))) private class TypeAliasExpansion( - val context: TypeAliasExpansionContext, val parent: TypeAliasExpansion?, val descriptor: TypeAliasDescriptor, val arguments: List, @@ -475,57 +511,28 @@ class TypeResolver( this.descriptor == descriptor || (parent?.isRecursion(descriptor) ?: false) } - private fun createTypeAliasExpansionFromSource( - c: TypeResolutionContext, - element: KtUserType, - descriptor: TypeAliasDescriptor, - argumentElements: List - ): TypeAliasExpansion { - val typeAliasParameters = descriptor.typeConstructor.parameters - val arguments = resolveTypeProjections(c, descriptor.typeConstructor, argumentElements) - - val mappedArguments: Map - val mappedElements: Map - if (typeAliasParameters.isNotEmpty()) { - val resultingArguments = HashMap() - val resultingElements = HashMap() - typeAliasParameters.forEachIndexed { i, typeParameterDescriptor -> - resultingArguments[typeParameterDescriptor] = arguments[i] - resultingElements[typeParameterDescriptor] = argumentElements[i] - } - mappedArguments = resultingArguments - mappedElements = resultingElements - } - else { - mappedArguments = emptyMap() - mappedElements = emptyMap() - } - - return TypeAliasExpansion(TypeAliasExpansionContext(element, mappedElements), null, descriptor, arguments, mappedArguments) - } - - private fun createNestedTypeAliasExpansion( - parent: TypeAliasExpansion, + private fun createTypeAliasExpansion( + parent: TypeAliasExpansion?, typeAliasDescriptor: TypeAliasDescriptor, - expandedArguments: List + arguments: List ): TypeAliasExpansion { - val mappedArguments = HashMap() - typeAliasDescriptor.typeConstructor.parameters.forEachIndexed { i, typeParameterDescriptor -> - mappedArguments[typeParameterDescriptor] = expandedArguments[i] - } - - return TypeAliasExpansion(parent.context, parent, typeAliasDescriptor, expandedArguments, mappedArguments) + val typeParameters = typeAliasDescriptor.declaredTypeParameters // TODO inner type aliases + val mappedArguments = typeParameters.zip(arguments).toMap() + return TypeAliasExpansion(parent, typeAliasDescriptor, arguments, mappedArguments) } private fun expandTypeAlias( c: TypeResolutionContext, typeAliasExpansion: TypeAliasExpansion, - annotations: Annotations + reportStrategy: TypeAliasExpansionReportStrategy, + annotations: Annotations, + recursionDepth: Int ): KotlinType { val originalProjection = TypeProjectionImpl(Variance.INVARIANT, typeAliasExpansion.descriptor.underlyingType) - val expandedProjection = expandTypeProjectionForTypeAlias(c, originalProjection, typeAliasExpansion, null, 1) + val expandedProjection = expandTypeProjectionForTypeAlias(c, originalProjection, typeAliasExpansion, null, reportStrategy, recursionDepth) + val expandedType = expandedProjection.type - if (expandedProjection.type.isError) return expandedProjection.type + if (expandedType.isError) return expandedType assert(expandedProjection.projectionKind == Variance.INVARIANT) { "Type alias expansion: result for ${typeAliasExpansion.descriptor} is ${expandedProjection.projectionKind}, should be invariant" @@ -535,9 +542,7 @@ class TypeResolver( originalProjection.type.isMarkedNullable, typeAliasExpansion.arguments, MemberScope.Empty) - return expandedProjection.type.replace( - newAnnotations = annotations, - newCapabilities = withAbbreviatedType(abbreviatedType)) + return expandedType.withAbbreviatedType(abbreviatedType) } private fun expandTypeProjectionForTypeAlias( @@ -545,6 +550,7 @@ class TypeResolver( originalProjection: TypeProjection, typeAliasExpansion: TypeAliasExpansion, typeParameterDescriptor: TypeParameterDescriptor?, + reportStrategy: TypeAliasExpansionReportStrategy, recursionDepth: Int ): TypeProjection { assertRecursionDepth(recursionDepth) { @@ -556,7 +562,7 @@ class TypeResolver( val typeAliasArgument = typeAliasExpansion.getReplacement(originalType.constructor) if (typeAliasArgument == null) { - return substituteNonArgumentTypeForTypeAlias(c, originalProjection, typeAliasExpansion, recursionDepth) + return substituteNonArgumentTypeForTypeAlias(c, originalProjection, typeAliasExpansion, reportStrategy, recursionDepth) } val originalVariance = @@ -578,14 +584,7 @@ class TypeResolver( argumentVariance else { if (originalVariance != argumentVariance && !typeAliasArgument.isStarProjection) { - val argumentElement = typeParameterDescriptor?.let { typeAliasExpansion.context.argumentElements[it] } - if (argumentElement != null && typeParameterDescriptor != null) { - c.trace.report(CONFLICTING_PROJECTION.on(argumentElement, typeParameterDescriptor)) - } - else { - c.trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on( - typeAliasExpansion.context.element, typeAliasExpansion.descriptor.underlyingType)) - } + reportStrategy.conflictingProjection(typeAliasExpansion.descriptor, typeParameterDescriptor, originalType) } argumentVariance } @@ -599,6 +598,7 @@ class TypeResolver( c: TypeResolutionContext, originalProjection: TypeProjection, typeAliasExpansion: TypeAliasExpansion, + reportStrategy: TypeAliasExpansionReportStrategy, recursionDepth: Int ): TypeProjection { val type = originalProjection.type @@ -611,27 +611,26 @@ class TypeResolver( } is TypeAliasDescriptor -> { if (typeAliasExpansion.isRecursion(typeDescriptor)) { - c.trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(typeAliasExpansion.context.element, typeDescriptor)) + reportStrategy.recursiveTypeAlias(typeDescriptor) return TypeProjectionImpl(Variance.INVARIANT, ErrorUtils.createErrorType("Recursive type alias: ${typeDescriptor.name}")) } val expandedArguments = type.arguments.mapIndexed { i, typeAliasArgument -> - expandTypeProjectionForTypeAlias(c, typeAliasArgument, typeAliasExpansion, typeConstructor.parameters[i], recursionDepth) + expandTypeProjectionForTypeAlias(c, typeAliasArgument, typeAliasExpansion, typeConstructor.parameters[i], reportStrategy, recursionDepth + 1) } - val nestedExpansion = createNestedTypeAliasExpansion(typeAliasExpansion, typeDescriptor, expandedArguments) + val nestedExpansion = createTypeAliasExpansion(typeAliasExpansion, typeDescriptor, expandedArguments) - val expandedType = expandTypeAlias(c, nestedExpansion, type.annotations) + val expandedType = expandTypeAlias(c, nestedExpansion, reportStrategy, type.annotations, recursionDepth + 1) - return TypeProjectionImpl(originalProjection.projectionKind, - if (expandedType.isError) expandedType else expandedType.replace(newCapabilities = withAbbreviatedType(type))) + return TypeProjectionImpl(originalProjection.projectionKind, expandedType.withAbbreviatedType(type)) } else -> { val substitutedArguments = type.arguments.mapIndexed { i, originalArgument -> - expandTypeProjectionForTypeAlias(c, originalArgument, typeAliasExpansion, typeConstructor.parameters[i], recursionDepth + 1) + expandTypeProjectionForTypeAlias(c, originalArgument, typeAliasExpansion, typeConstructor.parameters[i], reportStrategy, recursionDepth + 1) } - checkTypeArgumentsSubstitutionInTypeAliasExpansion(c, type, substitutedArguments, typeAliasExpansion) + checkTypeArgumentsSubstitutionInTypeAliasExpansion(type, substitutedArguments, reportStrategy) val substitutedType = type.replace(newArguments = substitutedArguments) @@ -641,16 +640,15 @@ class TypeResolver( } private fun checkTypeArgumentsSubstitutionInTypeAliasExpansion( - c: TypeResolutionContext, type: KotlinType, substitutedArguments: List, - typeAliasExpansion: TypeAliasExpansion + reportStrategy: TypeAliasExpansionReportStrategy ) { val typeSubstitutor = TypeSubstitutor.create(type) substitutedArguments.forEachIndexed { i, substitutedArgument -> val typeParameter = type.constructor.parameters[i] - DescriptorResolver.checkBoundsInTypeAlias(typeAliasExpansion.context.element, substitutedArgument.type, typeParameter, typeSubstitutor, c.trace) + DescriptorResolver.checkBoundsInTypeAlias(reportStrategy, substitutedArgument.type, typeParameter, typeSubstitutor) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt index 5e2cb7ad342..ae9e71d96ab 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/AbstractLazyMemberScope.kt @@ -17,10 +17,7 @@ package org.jetbrains.kotlin.resolve.lazy.descriptors import com.google.common.collect.Sets -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt index dc4e4ddef82..8ba6431cb9e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt @@ -47,6 +47,14 @@ fun TypeCapabilities.addCapability(clazz: Class, typeCap return CompositeTypeCapabilities(this, newCapabilities) } +fun TypeCapabilities.overrideCapability(clazz: Class, typeCapability: T): TypeCapabilities { + if (getCapability(clazz) === typeCapability) return this + val newCapabilities = SingletonTypeCapabilities(clazz, typeCapability) + if (this === org.jetbrains.kotlin.types.TypeCapabilities.NONE) return newCapabilities + + return CompositeTypeCapabilities(newCapabilities, this) +} + inline fun KotlinType.getCapability(): T? = getCapability(T::class.java)