diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 5a60b6be7f8..5cbf760b55d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -115,6 +115,7 @@ public interface Errors { DiagnosticFactory0 REIFIED_TYPE_IN_CATCH_CLAUSE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 GENERIC_THROWABLE_SUBCLASS = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 UNSUPPORTED_TYPEALIAS = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 RECURSIVE_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR); DiagnosticFactory3 UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION = DiagnosticFactory3.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 04acfe166e2..9b90f79bd43 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -417,6 +417,7 @@ public class DefaultErrorMessages { MAP.put(USELESS_ELVIS_ON_LAMBDA_EXPRESSION, "Left operand of elvis operator (?:) is a lambda expression"); MAP.put(CONFLICTING_UPPER_BOUNDS, "Upper bounds of {0} have empty intersection", NAME); + MAP.put(UNSUPPORTED_TYPEALIAS, "Type aliases are unsupported (min Kotlin language level: 1.1)"); MAP.put(RECURSIVE_TYPEALIAS_EXPANSION, "Recursive type alias in expansion: {0}", NAME); MAP.put(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION, "Type argument resulting from type alias expansion is not within required bounds for ''{2}'': " + diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtTypeAlias.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtTypeAlias.kt index 6013e813dc5..a95b9ba6791 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtTypeAlias.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtTypeAlias.kt @@ -17,7 +17,9 @@ package org.jetbrains.kotlin.psi import com.intellij.lang.ASTNode +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.stubs.KotlinTypeAliasStub import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes @@ -31,6 +33,10 @@ class KtTypeAlias : KtTypeParameterListOwnerStub, KtNamedDe fun isTopLevel(): Boolean = stub?.isTopLevel() ?: parent is KtFile + @IfNotParsed + fun getTypeAliasKeyword(): PsiElement? = + findChildByType(KtTokens.TYPE_ALIAS_KEYWORD) + @IfNotParsed fun getTypeReference(): KtTypeReference? = findChildByType(KtNodeTypes.TYPE_REFERENCE) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index cc1ab533042..0ba74dbaa97 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -29,6 +29,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.FunctionTypesKt; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.config.LanguageFeature; +import org.jetbrains.kotlin.config.LanguageFeatureSettings; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationSplitter; import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; @@ -61,9 +63,7 @@ import java.util.*; import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*; import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.lexer.KtTokens.*; -import static org.jetbrains.kotlin.resolve.BindingContext.CONSTRUCTOR; -import static org.jetbrains.kotlin.resolve.BindingContext.PACKAGE_TO_FILES; -import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_ALIAS; +import static org.jetbrains.kotlin.resolve.BindingContext.*; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveModalityFromModifiers; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers; @@ -79,6 +79,7 @@ public class DescriptorResolver { @NotNull private final VariableTypeResolver variableTypeResolver; @NotNull private final ExpressionTypingServices expressionTypingServices; @NotNull private final OverloadChecker overloadChecker; + @NotNull private final LanguageFeatureSettings languageFeatureSettings; public DescriptorResolver( @NotNull AnnotationResolver annotationResolver, @@ -88,7 +89,8 @@ public class DescriptorResolver { @NotNull SupertypeLoopChecker supertypeLoopsResolver, @NotNull VariableTypeResolver variableTypeResolver, @NotNull ExpressionTypingServices expressionTypingServices, - @NotNull OverloadChecker overloadChecker + @NotNull OverloadChecker overloadChecker, + @NotNull LanguageFeatureSettings languageFeatureSettings ) { this.annotationResolver = annotationResolver; this.builtIns = builtIns; @@ -98,6 +100,7 @@ public class DescriptorResolver { this.variableTypeResolver = variableTypeResolver; this.expressionTypingServices = expressionTypingServices; this.overloadChecker = overloadChecker; + this.languageFeatureSettings = languageFeatureSettings; } public List resolveSupertypes( @@ -675,21 +678,24 @@ public class DescriptorResolver { return variableDescriptor; } - @NotNull + @Nullable public TypeAliasDescriptor resolveTypeAliasDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @NotNull LexicalScope scope, @NotNull KtTypeAlias typeAlias, @NotNull final BindingTrace trace ) { + final KtTypeReference typeReference = typeAlias.getTypeReference(); + if (typeReference == null) return null; + KtModifierList modifierList = typeAlias.getModifierList(); Visibility visibility = resolveVisibilityFromModifiers(typeAlias, getDefaultVisibility(typeAlias, containingDeclaration)); Annotations allAnnotations = annotationResolver.resolveAnnotationsWithArguments(scope, modifierList, trace); Name name = KtPsiUtil.safeName(typeAlias.getName()); SourceElement sourceElement = KotlinSourceElementKt.toSourceElement(typeAlias); - LazyTypeAliasDescriptor typeAliasDescriptor = LazyTypeAliasDescriptor.create( - containingDeclaration, allAnnotations, name, sourceElement, visibility); + final LazyTypeAliasDescriptor typeAliasDescriptor = LazyTypeAliasDescriptor.create( + storageManager, trace, containingDeclaration, allAnnotations, name, sourceElement, visibility); List typeParameterDescriptors; final LexicalScope scopeWithTypeParameters; @@ -712,20 +718,25 @@ public class DescriptorResolver { } } - final KtTypeReference typeReference = typeAlias.getTypeReference(); + if (!languageFeatureSettings.supportsFeature(LanguageFeature.TypeAliases)) { + typeResolver.resolveType(scopeWithTypeParameters, typeReference, trace, true); + trace.report(UNSUPPORTED_TYPEALIAS.on(typeAlias.getTypeAliasKeyword())); + return null; + } typeAliasDescriptor.initialize( typeParameterDescriptors, - storageManager.createLazyValue(new Function0() { + DeferredType.create(storageManager, trace, new Function0() { @Override public KotlinType invoke() { return typeResolver.resolveAbbreviatedType(scopeWithTypeParameters, typeReference, trace, true); } }), - storageManager.createLazyValue(new Function0() { + DeferredType.create(storageManager, trace, new Function0() { @Override public KotlinType invoke() { - // TODO do not reparse + // TODO do not reparse type alias RHS, just expand it instead + // NB this messes up with diagnostics return typeResolver.resolveType(scopeWithTypeParameters, typeReference, trace, true); } })); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt index 3f84249a2a0..587d0122a3c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt @@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve import com.google.common.collect.HashMultimap import com.google.common.collect.Multimap import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageFeatureSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.incremental.KotlinLookupLocation @@ -44,7 +46,8 @@ class LazyTopDownAnalyzer( private val fileScopeProvider: FileScopeProvider, private val declarationScopeProvider: DeclarationScopeProvider, private val qualifiedExpressionResolver: QualifiedExpressionResolver, - private val identifierChecker: IdentifierChecker + private val identifierChecker: IdentifierChecker, + private val languageFeatureSettings: LanguageFeatureSettings ) { fun analyzeDeclarations(topDownAnalysisMode: TopDownAnalysisMode, declarations: Collection, outerDataFlowInfo: DataFlowInfo): TopDownAnalysisContext { @@ -207,6 +210,8 @@ class LazyTopDownAnalyzer( } private fun createTypeAliasDescriptors(c: TopDownAnalysisContext, topLevelFqNames: Multimap, typeAliases: List) { + if (!languageFeatureSettings.supportsFeature(LanguageFeature.TypeAliases)) return + for (typeAlias in typeAliases) { val descriptor = lazyDeclarationResolver.resolveToDescriptor(typeAlias) as TypeAliasDescriptor diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index 20b73479df2..4c1f500c878 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -369,8 +369,8 @@ class TypeResolver( } val collectedArgumentAsTypeProjections = - collectArgumentsForClassTypeConstructor(c, classDescriptor, qualifierResolutionResult.qualifierParts) - ?: return createErrorTypeAndResolveArguments(c, projectionFromAllQualifierParts, typeConstructor.toString()) + collectArgumentsForClassifierTypeConstructor(c, classDescriptor, qualifierResolutionResult.qualifierParts) + ?: return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor) assert(collectedArgumentAsTypeProjections.size <= parameters.size) { "Collected arguments count should be not greater then parameters count," + @@ -423,63 +423,70 @@ class TypeResolver( private fun resolveTypeForTypeAlias( c: TypeResolutionContext, annotations: Annotations, - typeAliasDescriptor: TypeAliasDescriptor, + descriptor: TypeAliasDescriptor, type: KtUserType, qualifierResolutionResult: QualifiedExpressionResolver.TypeQualifierResolutionResult ): PossiblyBareType { - val typeAliasConstructor = typeAliasDescriptor.typeConstructor + val typeConstructor = descriptor.typeConstructor val projectionFromAllQualifierParts = qualifierResolutionResult.allProjections - if (ErrorUtils.isError(typeAliasDescriptor)) { - return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeAliasConstructor) + if (ErrorUtils.isError(descriptor)) { + return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor) } - // TODO type arguments substitution for type parameters of outer classes - // TODO should we support type aliases as qualifiers? what about generics? + val parameters = typeConstructor.parameters - val typeAliasParameters = typeAliasDescriptor.declaredTypeParameters + val typeAliasQualifierPart = + qualifierResolutionResult.qualifierParts.lastOrNull() + ?: return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor) - val typeAliasQualifierPart = qualifierResolutionResult.qualifierParts.lastOrNull() - ?: return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeAliasConstructor) + val argumentElementsFromUserType = + collectArgumentsForClassifierTypeConstructor(c, descriptor, qualifierResolutionResult.qualifierParts) + ?: return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor) - // TODO appendDefaultArgumentsForInnerScope - val typeAliasArguments = typeAliasQualifierPart.typeArguments?.arguments.orEmpty() + val argumentsFromUserType = resolveTypeProjections(c, typeConstructor, argumentElementsFromUserType) + + val arguments = argumentsFromUserType + appendDefaultArgumentsForInnerScope(argumentsFromUserType.size, parameters) val reportStrategy = TracingTypeAliasExpansionReportStrategy( c.trace, type, typeAliasQualifierPart.typeArguments ?: typeAliasQualifierPart.expression, - typeAliasDescriptor, typeAliasDescriptor.declaredTypeParameters, typeAliasArguments) + descriptor, descriptor.declaredTypeParameters, + argumentElementsFromUserType // TODO arguments from inner scope + ) - if (typeAliasParameters.size != typeAliasArguments.size) { - reportStrategy.wrongNumberOfTypeArguments(typeAliasDescriptor, typeAliasParameters.size) - return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeAliasConstructor) + if (parameters.size != arguments.size) { + reportStrategy.wrongNumberOfTypeArguments(descriptor, parameters.size) + return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor) } return if (c.abbreviated) { - val arguments = resolveTypeProjections(c, typeAliasDescriptor.typeConstructor, typeAliasArguments) - val abbreviatedType = KotlinTypeImpl.create(annotations, typeAliasDescriptor.typeConstructor, false, arguments, MemberScope.Empty) + val abbreviatedType = KotlinTypeImpl.create(annotations, descriptor.typeConstructor, false, arguments, MemberScope.Empty) type(abbreviatedType) } else { - val arguments = resolveTypeProjections(c, typeAliasDescriptor.typeConstructor, typeAliasArguments) - val typeAliasExpansion = createTypeAliasExpansion(null, typeAliasDescriptor, arguments) - val expandedType = expandTypeAlias(c, typeAliasExpansion, reportStrategy, annotations, 0) + val typeAliasExpansion = createTypeAliasExpansion(null, descriptor, arguments) + val expandedType = expandTypeAlias(typeAliasExpansion, reportStrategy, annotations, 0) type(expandedType) } } private class TracingTypeAliasExpansionReportStrategy( val trace: BindingTrace, - val type: KtUserType, - val typeArgumentsOrTypeName: KtElement, + val type: KtUserType?, + val typeArgumentsOrTypeName: KtElement?, val typeAliasDescriptor: TypeAliasDescriptor, - val typeParameters: List, - val typeArguments: List + typeParameters: List, + typeArguments: List ) : TypeAliasExpansionReportStrategy { + constructor (trace: BindingTrace, typeAliasDescriptor: TypeAliasDescriptor) : this(trace, null, null, typeAliasDescriptor, emptyList(), emptyList()) + 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)) + if (typeArgumentsOrTypeName != null) { + trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeArgumentsOrTypeName, numberOfParameters, typeAliasDescriptor)) + } } override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, expandingType: KotlinType) { @@ -487,13 +494,15 @@ class TypeResolver( if (argumentElement != null && typeParameter != null) { trace.report(CONFLICTING_PROJECTION.on(argumentElement, typeParameter)) } - else { + else if (type != null) { trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on(type, typeAliasDescriptor.underlyingType)) } } override fun recursiveTypeAlias(typeAlias: TypeAliasDescriptor) { - trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(type, typeAlias)) + if (type != null) { + trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(type, typeAlias)) + } } override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) { @@ -503,7 +512,7 @@ class TypeResolver( if (argumentTypeReferenceElement != null) { trace.report(UPPER_BOUND_VIOLATED.on(argumentTypeReferenceElement, bound, argument)) } - else { + else if (type != null) { trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(type, bound, argument, typeParameter)) } } @@ -532,20 +541,19 @@ class TypeResolver( typeAliasDescriptor: TypeAliasDescriptor, arguments: List ): TypeAliasExpansion { - val typeParameters = typeAliasDescriptor.declaredTypeParameters // TODO inner type aliases + val typeParameters = typeAliasDescriptor.typeConstructor.parameters.map { it.original as TypeParameterDescriptor } val mappedArguments = typeParameters.zip(arguments).toMap() return TypeAliasExpansion(parent, typeAliasDescriptor, arguments, mappedArguments) } private fun expandTypeAlias( - c: TypeResolutionContext, typeAliasExpansion: TypeAliasExpansion, reportStrategy: TypeAliasExpansionReportStrategy, annotations: Annotations, recursionDepth: Int ): KotlinType { val originalProjection = TypeProjectionImpl(Variance.INVARIANT, typeAliasExpansion.descriptor.underlyingType) - val expandedProjection = expandTypeProjectionForTypeAlias(c, originalProjection, typeAliasExpansion, null, reportStrategy, recursionDepth) + val expandedProjection = expandTypeProjectionForTypeAlias(originalProjection, typeAliasExpansion, null, reportStrategy, recursionDepth) val expandedType = expandedProjection.type if (expandedType.isError) return expandedType @@ -564,7 +572,6 @@ class TypeResolver( } private fun expandTypeProjectionForTypeAlias( - c: TypeResolutionContext, originalProjection: TypeProjection, typeAliasExpansion: TypeAliasExpansion, typeParameterDescriptor: TypeParameterDescriptor?, @@ -580,7 +587,7 @@ class TypeResolver( val typeAliasArgument = typeAliasExpansion.getReplacement(originalType.constructor) if (typeAliasArgument == null) { - return substituteNonArgumentTypeForTypeAlias(c, originalProjection, typeAliasExpansion, reportStrategy, recursionDepth) + return substituteNonArgumentTypeForTypeAlias(originalProjection, typeAliasExpansion, reportStrategy, recursionDepth) } val originalVariance = @@ -613,7 +620,6 @@ class TypeResolver( } private fun substituteNonArgumentTypeForTypeAlias( - c: TypeResolutionContext, originalProjection: TypeProjection, typeAliasExpansion: TypeAliasExpansion, reportStrategy: TypeAliasExpansionReportStrategy, @@ -634,18 +640,18 @@ class TypeResolver( } val expandedArguments = type.arguments.mapIndexed { i, typeAliasArgument -> - expandTypeProjectionForTypeAlias(c, typeAliasArgument, typeAliasExpansion, typeConstructor.parameters[i], reportStrategy, recursionDepth + 1) + expandTypeProjectionForTypeAlias(typeAliasArgument, typeAliasExpansion, typeConstructor.parameters[i], reportStrategy, recursionDepth + 1) } val nestedExpansion = createTypeAliasExpansion(typeAliasExpansion, typeDescriptor, expandedArguments) - val expandedType = expandTypeAlias(c, nestedExpansion, reportStrategy, type.annotations, recursionDepth + 1) + val expandedType = expandTypeAlias(nestedExpansion, reportStrategy, type.annotations, recursionDepth + 1) return TypeProjectionImpl(originalProjection.projectionKind, expandedType.withAbbreviatedType(type)) } else -> { val substitutedArguments = type.arguments.mapIndexed { i, originalArgument -> - expandTypeProjectionForTypeAlias(c, originalArgument, typeAliasExpansion, typeConstructor.parameters[i], reportStrategy, recursionDepth + 1) + expandTypeProjectionForTypeAlias(originalArgument, typeAliasExpansion, typeConstructor.parameters[i], reportStrategy, recursionDepth + 1) } val substitutedType = type.replace(newArguments = substitutedArguments) @@ -677,8 +683,11 @@ class TypeResolver( c: TypeResolutionContext, arguments: List, typeConstructor: TypeConstructor - ) = - createErrorTypeAndResolveArguments(c, arguments, "[Error type: $typeConstructor]") + ): PossiblyBareType = + type(ErrorUtils.createErrorTypeWithArguments( + "$typeConstructor", + resolveTypeProjectionsWithErrorConstructor(c, arguments) + )) // Returns true in case when at least one argument for this class could be specified // It could be always equal to 'typeConstructor.parameters.isNotEmpty()' unless local classes could captured type parameters @@ -691,30 +700,30 @@ class TypeResolver( // } // // It's needed to determine whether this particular type could be bare - private fun isPossibleToSpecifyTypeArgumentsFor(classDescriptor: ClassDescriptor): Boolean { + private fun isPossibleToSpecifyTypeArgumentsFor(classifierDescriptor: ClassifierDescriptorWithTypeParameters): Boolean { // First parameter relates to the innermost declaration // If it's declared in function there - val firstTypeParameter = classDescriptor.typeConstructor.parameters.firstOrNull() ?: return false + val firstTypeParameter = classifierDescriptor.typeConstructor.parameters.firstOrNull() ?: return false return firstTypeParameter.original.containingDeclaration is ClassDescriptor } - private fun collectArgumentsForClassTypeConstructor( + private fun collectArgumentsForClassifierTypeConstructor( c: TypeResolutionContext, - classDescriptor: ClassDescriptor, + classifierDescriptor: ClassifierDescriptorWithTypeParameters, qualifierParts: List ): List? { - val classDescriptorChain = classDescriptor.classDescriptorChain() + val classifierDescriptorChain = classifierDescriptor.classifierDescriptorsFromInnerToOuter() val reversedQualifierParts = qualifierParts.asReversed() var wasStatic = false - var result = SmartList() + val result = SmartList() - val classChainLastIndex = Math.min(classDescriptorChain.size, reversedQualifierParts.size) - 1 + val classifierChainLastIndex = Math.min(classifierDescriptorChain.size, reversedQualifierParts.size) - 1 - for (index in 0..classChainLastIndex) { + for (index in 0..classifierChainLastIndex) { val qualifierPart = reversedQualifierParts[index] val currentArguments = qualifierPart.typeArguments?.arguments.orEmpty() - val declaredTypeParameters = classDescriptorChain[index].declaredTypeParameters + val declaredTypeParameters = classifierDescriptorChain[index].declaredTypeParameters val currentParameters = if (wasStatic) emptyList() else declaredTypeParameters if (wasStatic && currentArguments.isNotEmpty() && declaredTypeParameters.isNotEmpty()) { @@ -725,7 +734,8 @@ class TypeResolver( if (currentArguments.size != currentParameters.size) { c.trace.report( WRONG_NUMBER_OF_TYPE_ARGUMENTS.on( - qualifierPart.typeArguments ?: qualifierPart.expression, currentParameters.size, classDescriptorChain[index] + qualifierPart.typeArguments ?: qualifierPart.expression, + currentParameters.size, classifierDescriptorChain[index] ) ) return null @@ -733,12 +743,12 @@ class TypeResolver( result.addAll(currentArguments) - wasStatic = wasStatic || !classDescriptorChain[index].isInner + wasStatic = wasStatic || !classifierDescriptorChain[index].isInner } val nonClassQualifierParts = reversedQualifierParts.subList( - Math.min(classChainLastIndex + 1, reversedQualifierParts.size), + Math.min(classifierChainLastIndex + 1, reversedQualifierParts.size), reversedQualifierParts.size) for (qualifierPart in nonClassQualifierParts) { @@ -748,12 +758,12 @@ class TypeResolver( } } - val parameters = classDescriptor.typeConstructor.parameters + val parameters = classifierDescriptor.typeConstructor.parameters if (result.size < parameters.size) { val typeParametersToSpecify = parameters.subList(result.size, parameters.size).takeWhile { it.original.containingDeclaration is ClassDescriptor } if (typeParametersToSpecify.any { parameter -> !parameter.isDeclaredInScope(c) }) { - c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(qualifierParts.last().expression, parameters.size, classDescriptor)) + c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(qualifierParts.last().expression, parameters.size, classifierDescriptor)) return null } } @@ -761,11 +771,16 @@ class TypeResolver( return result } - private fun ClassifierDescriptor?.classDescriptorChain(): List - = generateSequence({ this as? ClassDescriptor }, { it.containingDeclaration as? ClassDescriptor }).toList() + private fun ClassifierDescriptor?.classifierDescriptorsFromInnerToOuter(): List = + generateSequence( + { this as? ClassifierDescriptorWithTypeParameters }, + { it.containingDeclaration as? ClassifierDescriptorWithTypeParameters } + ).toList() private fun TypeParameterDescriptor.isDeclaredInScope(c: TypeResolutionContext): Boolean { - assert(containingDeclaration is ClassDescriptor) { "This function is implemented for classes only, but $containingDeclaration was given" } + assert(containingDeclaration is ClassifierDescriptorWithTypeParameters) { + "This function is implemented for ClassifierDescriptorWithTypeParameters only, but $containingDeclaration was given" + } // This function checks whether this@TypeParameterDescriptor ()is reachable from current scope by it's name // The only way it can be is that we are within class that contains it @@ -776,11 +791,11 @@ class TypeResolver( val contributedClassifier = c.scope.findClassifier(name, NoLookupLocation.WHEN_RESOLVING_DEFAULT_TYPE_ARGUMENTS) ?: return false if (contributedClassifier.typeConstructor == typeConstructor) return true - return c.scope.ownerDescriptor.isInsideOfClass(original.containingDeclaration as ClassDescriptor) + return c.scope.ownerDescriptor.isInsideOfClass(original.containingDeclaration as ClassifierDescriptorWithTypeParameters) } - private fun DeclarationDescriptor.isInsideOfClass(classDescriptor: ClassDescriptor) - = generateSequence(this, { it.containingDeclaration }).any { it.original == classDescriptor } + private fun DeclarationDescriptor.isInsideOfClass(classifierDescriptor: ClassifierDescriptorWithTypeParameters) + = generateSequence(this, { it.containingDeclaration }).any { it.original == classifierDescriptor } private fun resolveTypeProjectionsWithErrorConstructor( @@ -789,13 +804,6 @@ class TypeResolver( message: String = "Error type for resolving type projections" ) = resolveTypeProjections(c, ErrorUtils.createErrorTypeConstructor(message), argumentElements) - private fun createErrorTypeAndResolveArguments( - c: TypeResolutionContext, - argumentElements: List, - message: String = "" - ): PossiblyBareType - = type(ErrorUtils.createErrorTypeWithArguments(message, resolveTypeProjectionsWithErrorConstructor(c, argumentElements))) - // In cases like // class Outer { // inner class Inner 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 ae9e71d96ab..5cbb451c2f0 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 @@ -124,7 +124,7 @@ protected constructor( } private fun doGetTypeAliases(name: Name): Collection = - declarationProvider.getTypeAliasDeclarations(name).map { ktTypeAlias -> + declarationProvider.getTypeAliasDeclarations(name).mapNotNull { ktTypeAlias -> c.descriptorResolver.resolveTypeAliasDescriptor( thisDescriptor, getScopeForMemberDeclarationResolution(ktTypeAlias), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeAliasDescriptor.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeAliasDescriptor.kt index 93d268b99af..d4c465e6dc0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeAliasDescriptor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyTypeAliasDescriptor.kt @@ -20,10 +20,16 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.AbstractTypeAliasDescriptor import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.storage.NotNullLazyValue +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.DeferredType import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.Variance class LazyTypeAliasDescriptor( + private val storageManager: StorageManager, + private val trace: BindingTrace, containingDeclaration: DeclarationDescriptor, annotations: Annotations, name: Name, @@ -32,30 +38,50 @@ class LazyTypeAliasDescriptor( ) : AbstractTypeAliasDescriptor(containingDeclaration, annotations, name, sourceElement, visibility), TypeAliasDescriptor { - private lateinit var underlyingTypeImpl: NotNullLazyValue - private lateinit var expandedTypeImpl: NotNullLazyValue + override lateinit var underlyingType: KotlinType private set + override lateinit var expandedType: KotlinType private set - override val underlyingType: KotlinType get() = underlyingTypeImpl() - override val expandedType: KotlinType get() = expandedTypeImpl() + private val lazyTypeConstructorParameters = + storageManager.createLazyValue { this.computeConstructorTypeParameters() } fun initialize( declaredTypeParameters: List, - lazyUnderlyingType: NotNullLazyValue, - lazyExpandedType: NotNullLazyValue + underlyingType: KotlinType, + expandedType: KotlinType ) { super.initialize(declaredTypeParameters) - this.underlyingTypeImpl = lazyUnderlyingType - this.expandedTypeImpl = lazyExpandedType + this.underlyingType = underlyingType + this.expandedType = expandedType } + override fun substitute(substitutor: TypeSubstitutor): TypeAliasDescriptor { + if (substitutor.isEmpty) return this + val substituted = LazyTypeAliasDescriptor(storageManager, trace, + containingDeclaration, annotations, name, source, visibility) + substituted.initialize(declaredTypeParameters, + DeferredType.create(storageManager, trace) { + substitutor.substitute(underlyingType, Variance.INVARIANT) + }, + DeferredType.create(storageManager, trace) { + substitutor.substitute(expandedType, Variance.INVARIANT) + }) + return substituted + } + + override fun getTypeConstructorTypeParameters(): List = + lazyTypeConstructorParameters() + companion object { @JvmStatic fun create( + storageManager: StorageManager, + trace: BindingTrace, containingDeclaration: DeclarationDescriptor, annotations: Annotations, name: Name, sourceElement: SourceElement, visibility: Visibility ): LazyTypeAliasDescriptor = - LazyTypeAliasDescriptor(containingDeclaration, annotations, name, sourceElement, visibility) + LazyTypeAliasDescriptor(storageManager, trace, + containingDeclaration, annotations, name, sourceElement, visibility) } } diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java index b1b51a710e0..2be493bf10b 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java @@ -172,12 +172,17 @@ public class DescriptorSerializer { } for (DeclarationDescriptor descriptor : sort(DescriptorUtils.getAllDescriptors(classDescriptor.getUnsubstitutedInnerClassesScope()))) { - int name = getSimpleNameIndex(descriptor.getName()); - if (isEnumEntry(descriptor)) { - builder.addEnumEntry(enumEntryProto((ClassDescriptor) descriptor)); + if (descriptor instanceof TypeAliasDescriptor) { + builder.addTypeAlias(typeAliasProto((TypeAliasDescriptor) descriptor)); } else { - builder.addNestedClassName(name); + int name = getSimpleNameIndex(descriptor.getName()); + if (isEnumEntry(descriptor)) { + builder.addEnumEntry(enumEntryProto((ClassDescriptor) descriptor)); + } + else { + builder.addNestedClassName(name); + } } } @@ -520,9 +525,8 @@ public class DescriptorSerializer { assert possiblyInnerType != null : "possiblyInnerType should not be null in case of class"; fillFromPossiblyInnerType(builder, possiblyInnerType); - } - if (descriptor instanceof TypeParameterDescriptor) { + else if (descriptor instanceof TypeParameterDescriptor) { TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) descriptor; if (typeParameter.getContainingDeclaration() == containingDeclaration) { builder.setTypeParameterName(getSimpleNameIndex(typeParameter.getName())); @@ -533,7 +537,7 @@ public class DescriptorSerializer { assert type.getArguments().isEmpty() : "Found arguments for type constructor build on type parameter: " + descriptor; } - if (descriptor instanceof TypeAliasDescriptor) { + else if (descriptor instanceof TypeAliasDescriptor) { PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type); assert possiblyInnerType != null : "possiblyInnerType should not be null in case of type alias"; fillFromPossiblyInnerType(builder, possiblyInnerType); diff --git a/compiler/testData/diagnostics/tests/typealias/isAsWithTypeAlias.kt b/compiler/testData/diagnostics/tests/typealias/isAsWithTypeAlias.kt new file mode 100644 index 00000000000..bf998f4817c --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/isAsWithTypeAlias.kt @@ -0,0 +1,5 @@ +typealias S = String + +fun test1(x: Any) = x is S +fun test2(x: Any) = x as S +fun test3(x: Any) = x as? S diff --git a/compiler/testData/diagnostics/tests/typealias/isAsWithTypeAlias.txt b/compiler/testData/diagnostics/tests/typealias/isAsWithTypeAlias.txt new file mode 100644 index 00000000000..cb951ee7162 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/isAsWithTypeAlias.txt @@ -0,0 +1,6 @@ +package + +public typealias S = kotlin.String +public fun test1(/*0*/ x: kotlin.Any): kotlin.Boolean +public fun test2(/*0*/ x: kotlin.Any): S [= kotlin.String] +public fun test3(/*0*/ x: kotlin.Any): S [= kotlin.String?] diff --git a/compiler/testData/diagnostics/tests/typealias/nested.kt b/compiler/testData/diagnostics/tests/typealias/nested.kt new file mode 100644 index 00000000000..0916f68de9b --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/nested.kt @@ -0,0 +1,24 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +class Pair(val x1: T1, val x2: T2) + +class C { + typealias P2 = Pair + + fun p() = P2(1, 1) + fun first(p: P2) = p.x1 + fun second(p: P2) = p.x2 +} + +val p1 = Pair(1, 1) + +val test1: Int = C().first(p1) +val test2: Int = C().second(p1) + +fun C.testExtFun1(x: C.P2) = x + +fun C.testExtFun2(): C.P2 { + val x: C.P2 = p() + val y = C.P2(1, 1) + return x +} diff --git a/compiler/testData/diagnostics/tests/typealias/nested.txt b/compiler/testData/diagnostics/tests/typealias/nested.txt new file mode 100644 index 00000000000..cceebed74f3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/nested.txt @@ -0,0 +1,27 @@ +package + +public val p1: Pair +public val test1: kotlin.Int +public val test2: kotlin.Int +public fun C.testExtFun1(/*0*/ x: C.P2 [= Pair]): C.P2 [= Pair] +public fun C.testExtFun2(): C.P2 [= Pair] + +public final class C { + public typealias P2 = Pair + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun first(/*0*/ p: C.P2 [= Pair]): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun p(): Pair + public final fun second(/*0*/ p: C.P2 [= Pair]): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Pair { + public constructor Pair(/*0*/ x1: T1, /*1*/ x2: T2) + public final val x1: T1 + public final val x2: T2 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/typealias/nestedCapturingTypeParameters.kt b/compiler/testData/diagnostics/tests/typealias/nestedCapturingTypeParameters.kt new file mode 100644 index 00000000000..67fbafb45f6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/nestedCapturingTypeParameters.kt @@ -0,0 +1,21 @@ +class Pair(val x1: T1, val x2: T2) + +class C { + typealias P2 = Pair + typealias PT2 = Pair + + fun first(p: P2) = p.x1 + fun second(p: P2) = p.x2 + + fun first2(p: PT2) = p.x1 + fun second2(p: PT2) = p.x2 +} + +val p1 = Pair(1, 1) +val p2 = Pair(1, "") + +val test1: Int = C().first(p1) +val test2: Int = C().second(p1) + +val test3: Int = C().first2(p2) +val test4: String = C().second2(p2) diff --git a/compiler/testData/diagnostics/tests/typealias/nestedCapturingTypeParameters.txt b/compiler/testData/diagnostics/tests/typealias/nestedCapturingTypeParameters.txt new file mode 100644 index 00000000000..96a6c73839a --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/nestedCapturingTypeParameters.txt @@ -0,0 +1,30 @@ +package + +public val p1: Pair +public val p2: Pair +public val test1: kotlin.Int +public val test2: kotlin.Int +public val test3: kotlin.Int +public val test4: kotlin.String + +public final class C { + public typealias P2 /*captured type parameters: /*0*/ T*/ = Pair + public typealias PT2 /*captured type parameters: /*1*/ T*/ = Pair + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final fun first(/*0*/ p: C.P2 [= Pair]): T + public final fun first2(/*0*/ p: C.PT2 [= Pair]): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun second(/*0*/ p: C.P2 [= Pair]): T + public final fun second2(/*0*/ p: C.PT2 [= Pair]): T2 + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Pair { + public constructor Pair(/*0*/ x1: T1, /*1*/ x2: T2) + public final val x1: T1 + public final val x2: T2 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/typealias/nestedSubstituted.kt b/compiler/testData/diagnostics/tests/typealias/nestedSubstituted.kt new file mode 100644 index 00000000000..b045cd7bbdc --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/nestedSubstituted.kt @@ -0,0 +1,9 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER + +class Pair(val x1: T1, val x2: T2) + +class C { + typealias P2 = Pair +} + +val p1: C.P2 = Pair("", 1) diff --git a/compiler/testData/diagnostics/tests/typealias/nestedSubstituted.txt b/compiler/testData/diagnostics/tests/typealias/nestedSubstituted.txt new file mode 100644 index 00000000000..afd7a55e076 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/nestedSubstituted.txt @@ -0,0 +1,20 @@ +package + +public val p1: C.P2 [= Pair] + +public final class C { + public typealias P2 /*captured type parameters: /*0*/ T*/ = Pair + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Pair { + public constructor Pair(/*0*/ x1: T1, /*1*/ x2: T2) + public final val x1: T1 + public final val x2: T2 + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/typealias/recursive.kt b/compiler/testData/diagnostics/tests/typealias/recursive.kt index d64150b2e15..97ea09f10ee 100644 --- a/compiler/testData/diagnostics/tests/typealias/recursive.kt +++ b/compiler/testData/diagnostics/tests/typealias/recursive.kt @@ -1,4 +1,4 @@ -typealias A = B -typealias B = A +typealias A = B +typealias B = A val x: A = TODO() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt index 1b355a97f89..be2cbc6fc13 100644 --- a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt +++ b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt @@ -3,13 +3,13 @@ class Out class Inv typealias In1 = In -typealias In2 = In<in T> -typealias In3 = In<out T> +typealias In2 = In<in T> +typealias In3 = In<out T> typealias In4 = In<*> typealias Out1 = Out -typealias Out2 = Out<in T> -typealias Out3 = Out<out T> +typealias Out2 = Out<in T> +typealias Out3 = Out<out T> typealias Out4 = Out<*> typealias Inv1 = Inv diff --git a/compiler/testData/diagnostics/tests/typealias/unsupportedTypeAlias.kt b/compiler/testData/diagnostics/tests/typealias/unsupportedTypeAlias.kt new file mode 100644 index 00000000000..f027cfc8186 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/unsupportedTypeAlias.kt @@ -0,0 +1,13 @@ +// !LANGUAGE: -TypeAliases + +class C + +typealias S = String +typealias L = List +typealias CA = C + +val test1: S = "" + +fun test2(x: L<S>) = x + +class Test3 : CA() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/unsupportedTypeAlias.txt b/compiler/testData/diagnostics/tests/typealias/unsupportedTypeAlias.txt new file mode 100644 index 00000000000..58a2918308b --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/unsupportedTypeAlias.txt @@ -0,0 +1,18 @@ +package + +public val test1: [ERROR : S] +public fun test2(/*0*/ x: [ERROR : L]<[ERROR : S]>): [ERROR : L]<[ERROR : S]> + +public final class C { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Test3 { + public constructor Test3() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/loadJava/compiledKotlin/typealias/Nested.kt b/compiler/testData/loadJava/compiledKotlin/typealias/Nested.kt new file mode 100644 index 00000000000..263571951e8 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/typealias/Nested.kt @@ -0,0 +1,18 @@ +//ALLOW_AST_ACCESS +package test + +open class Pair +open class Triple + +class Outer { + inner class InnerTest1: Pair() + typealias Test1 = Pair + + class Nested { + typealias Test2 = Pair + } + + inner class Inner { + typealias Test3 = Triple + } +} diff --git a/compiler/testData/loadJava/compiledKotlin/typealias/Nested.txt b/compiler/testData/loadJava/compiledKotlin/typealias/Nested.txt new file mode 100644 index 00000000000..4d70fd2fa35 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/typealias/Nested.txt @@ -0,0 +1,28 @@ +package test + +public final class Outer { + public typealias Test1 /*captured type parameters: /*1*/ X*/ = test.Pair + /*primary*/ public constructor Outer() + + public final inner class Inner /*captured type parameters: /*1*/ X*/ { + public typealias Test3 /*captured type parameters: /*1*/ Z, /*2*/ X*/ = test.Triple + /*primary*/ public constructor Inner() + } + + public final inner class InnerTest1 /*captured type parameters: /*1*/ X*/ : test.Pair { + /*primary*/ public constructor InnerTest1() + } + + public final class Nested { + public typealias Test2 /*captured type parameters: /*1*/ Y*/ = test.Pair + /*primary*/ public constructor Nested() + } +} + +public open class Pair { + /*primary*/ public constructor Pair() +} + +public open class Triple { + /*primary*/ public constructor Triple() +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 8bef8f1a576..ba30eb16fcc 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -19167,6 +19167,30 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("isAsWithTypeAlias.kt") + public void testIsAsWithTypeAlias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/isAsWithTypeAlias.kt"); + doTest(fileName); + } + + @TestMetadata("nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/nested.kt"); + doTest(fileName); + } + + @TestMetadata("nestedCapturingTypeParameters.kt") + public void testNestedCapturingTypeParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/nestedCapturingTypeParameters.kt"); + doTest(fileName); + } + + @TestMetadata("nestedSubstituted.kt") + public void testNestedSubstituted() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/nestedSubstituted.kt"); + doTest(fileName); + } + @TestMetadata("parameterRestrictions.kt") public void testParameterRestrictions() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt"); @@ -19226,6 +19250,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/typeAliasObjectWithInvoke.kt"); doTest(fileName); } + + @TestMetadata("unsupportedTypeAlias.kt") + public void testUnsupportedTypeAlias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/unsupportedTypeAlias.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/unit") diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index ef2ebd1655a..a5b4ed580e3 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -4815,6 +4815,12 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Generic.kt"); doTestCompiledKotlin(fileName); } + + @TestMetadata("Nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Nested.kt"); + doTestCompiledKotlin(fileName); + } } @TestMetadata("compiler/testData/loadJava/compiledKotlin/visibility") diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java index 5408c063f7f..0ba6457319f 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java @@ -3048,6 +3048,12 @@ public class LoadKotlinWithTypeTableTestGenerated extends AbstractLoadKotlinWith String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Generic.kt"); doTest(fileName); } + + @TestMetadata("Nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Nested.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/loadJava/compiledKotlin/visibility") diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java index 776a280fc2d..438218532f8 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java @@ -3050,6 +3050,12 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Generic.kt"); doTest(fileName); } + + @TestMetadata("Nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Nested.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/loadJava/compiledKotlin/visibility") diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt index 3d450b96da4..a0bb04671bd 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/AbstractTypeAliasDescriptor.kt @@ -44,24 +44,19 @@ abstract class AbstractTypeAliasDescriptor( override fun accept(visitor: DeclarationDescriptorVisitor, data: D): R = visitor.visitTypeAliasDescriptor(this, data) - override fun isInner(): Boolean = false // TODO treat all nested type aliases as inner? + override fun isInner(): Boolean = + containingDeclaration !is PackageFragmentDescriptor override fun getDeclaredTypeParameters(): List = declaredTypeParametersImpl override val classDescriptor: ClassDescriptor? - get() = expandedType.let { expandedType -> - if (expandedType.isError) null else expandedType.constructor.declarationDescriptor as? ClassDescriptor - } + get() = if (expandedType.isError) null else expandedType.constructor.declarationDescriptor as? ClassDescriptor override fun getModality() = Modality.FINAL override fun getVisibility() = visibilityImpl - override fun substitute(substitutor: TypeSubstitutor): TypeAliasDescriptor = - if (substitutor.isEmpty) this - else TODO("typealias doSubstitute") - override fun getDefaultType(): KotlinType = TODO("typealias getDefaultType") @@ -70,12 +65,14 @@ abstract class AbstractTypeAliasDescriptor( override fun toString(): String = "typealias ${name.asString()}" + protected abstract fun getTypeConstructorTypeParameters(): List + private val typeConstructor = object : TypeConstructor { override fun getDeclarationDescriptor(): TypeAliasDescriptor = this@AbstractTypeAliasDescriptor override fun getParameters(): List = - declarationDescriptor.declaredTypeParameters // TODO type parameters of outer class + getTypeConstructorTypeParameters() override fun getSupertypes(): Collection = declarationDescriptor.underlyingType.constructor.supertypes diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/typeParameterUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/typeParameterUtils.kt index 0b5f1090c95..bf31ad66de6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/typeParameterUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/typeParameterUtils.kt @@ -23,7 +23,7 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull -fun ClassDescriptor.computeConstructorTypeParameters(): List { +fun ClassifierDescriptorWithTypeParameters.computeConstructorTypeParameters(): List { val declaredParameters = declaredTypeParameters if (!isInner && containingDeclaration !is CallableDescriptor) return declaredParameters diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index 5d82ec6630e..4bb6bbf9fcb 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -810,10 +810,24 @@ internal class DescriptorRendererImpl( renderVisibility(typeAlias.visibility, builder) builder.append(renderKeyword("typealias")).append(" ") renderName(typeAlias, builder) + renderTypeParameters(typeAlias.declaredTypeParameters, builder, true) + renderCapturedTypeParametersIfRequired(typeAlias, builder) + builder.append(" = ").append(renderType(typeAlias.underlyingType)) } + private fun renderCapturedTypeParametersIfRequired(classifier: ClassifierDescriptorWithTypeParameters, builder: StringBuilder) { + val typeParameters = classifier.declaredTypeParameters + val typeConstructorParameters = classifier.typeConstructor.parameters + + if (verbose && classifier.isInner && typeConstructorParameters.size > typeParameters.size) { + builder.append(" /*captured type parameters: ") + renderTypeParameterList(builder, typeConstructorParameters.subList(typeParameters.size, typeConstructorParameters.size)) + builder.append("*/") + } + } + /* CLASSES */ private fun renderClass(klass: ClassDescriptor, builder: StringBuilder) { val isEnumEntry = klass.kind == ClassKind.ENUM_ENTRY @@ -844,14 +858,7 @@ internal class DescriptorRendererImpl( val typeParameters = klass.declaredTypeParameters renderTypeParameters(typeParameters, builder, false) - - if (verbose && klass.isInner && klass.typeConstructor.parameters.size > typeParameters.size) { - builder.append(" /*captured type parameters: ") - val constructorTypeParameters = klass.typeConstructor.parameters - renderTypeParameterList( - builder, constructorTypeParameters.subList(typeParameters.size, constructorTypeParameters.size)) - builder.append("*/") - } + renderCapturedTypeParametersIfRequired(klass, builder) if (!klass.kind.isSingleton && classWithPrimaryConstructor) { val primaryConstructor = klass.unsubstitutedPrimaryConstructor diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/InnerClassesScopeWrapper.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/InnerClassesScopeWrapper.kt index 9367427a37a..23f5fcc7c6a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/InnerClassesScopeWrapper.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/InnerClassesScopeWrapper.kt @@ -17,16 +17,22 @@ package org.jetbrains.kotlin.resolve.scopes import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters +import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.Printer class InnerClassesScopeWrapper(val workerScope: MemberScope) : MemberScopeImpl() { - override fun getContributedClassifier(name: Name, location: LookupLocation) = workerScope.getContributedClassifier(name, location) as? ClassDescriptor + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = + workerScope.getContributedClassifier(name, location)?.let { + it as? ClassDescriptor ?: it as? TypeAliasDescriptor + } - override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List { + override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List { val restrictedFilter = kindFilter.restrictedToKindsOrNull(DescriptorKindFilter.CLASSIFIERS_MASK) ?: return listOf() - return workerScope.getContributedDescriptors(restrictedFilter, nameFilter).filterIsInstance() + return workerScope.getContributedDescriptors(restrictedFilter, nameFilter).filterIsInstance() } override fun printScopeStructure(p: Printer) { diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt index 14131c14479..87875ee820f 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt @@ -82,7 +82,7 @@ class TypeDeserializer( proto.hasTypeParameterName() -> { val container = c.containingDeclaration val typeParameters = when (container) { - is ClassDescriptor -> container.typeConstructor.parameters + is ClassifierDescriptorWithTypeParameters -> container.typeConstructor.parameters is CallableDescriptor -> container.typeParameters else -> emptyList() } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt index 568ea2f00f4..7082f4a0efa 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt @@ -25,6 +25,8 @@ import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.Variance interface DeserializedMemberDescriptor : MemberDescriptor { val proto: MessageLite @@ -146,11 +148,9 @@ class DeserializedTypeAliasDescriptor( ) : AbstractTypeAliasDescriptor(containingDeclaration, annotations, name, SourceElement.NO_SOURCE, visibility), DeserializedMemberDescriptor { - private lateinit var underlyingTypeImpl: KotlinType - private lateinit var expandedTypeImpl: KotlinType - - override val underlyingType: KotlinType get() = underlyingTypeImpl - override val expandedType: KotlinType get() = expandedTypeImpl + override lateinit var underlyingType: KotlinType private set + override lateinit var expandedType: KotlinType private set + private lateinit var typeConstructorParameters: List fun initialize( declaredTypeParameters: List, @@ -158,7 +158,22 @@ class DeserializedTypeAliasDescriptor( expandedType: KotlinType ) { initialize(declaredTypeParameters) - underlyingTypeImpl = underlyingType - expandedTypeImpl = expandedType + this.underlyingType = underlyingType + this.expandedType = expandedType + typeConstructorParameters = computeConstructorTypeParameters() } + + override fun substitute(substitutor: TypeSubstitutor): TypeAliasDescriptor { + if (substitutor.isEmpty) return this + val substituted = DeserializedTypeAliasDescriptor(containingDeclaration, annotations, name, visibility, proto, nameResolver, typeTable, containerSource) + substituted.initialize(declaredTypeParameters, + substitutor.safeSubstitute(underlyingType, Variance.INVARIANT), + substitutor.safeSubstitute(expandedType, Variance.INVARIANT)) + + return substituted + } + + override fun getTypeConstructorTypeParameters(): List = + typeConstructorParameters + } diff --git a/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java index 67fdde47850..38460c7a16b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java @@ -3048,6 +3048,12 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Generic.kt"); doTest(fileName); } + + @TestMetadata("Nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/typealias/Nested.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/loadJava/compiledKotlin/visibility")