From a4406687f197de76cbf9ae9c53c53544f57140b0 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 26 Apr 2016 15:25:31 +0300 Subject: [PATCH] KT-11588 Type aliases Resolution & expansion for type aliases. NB: Nested type aliases capturing type parameters of outer classes are not supported yet. --- ...elegatePackageMemberDeclarationProvider.kt | 4 +- .../jetbrains/kotlin/diagnostics/Errors.java | 9 +- .../rendering/DefaultErrorMessages.java | 10 +- .../kotlin/resolve/BindingContext.java | 3 +- .../kotlin/resolve/BodiesResolveContext.java | 7 +- .../kotlin/resolve/DescriptorResolver.java | 104 ++++++- .../resolve/FunctionDescriptorResolver.kt | 2 +- .../kotlin/resolve/LazyTopDownAnalyzer.kt | 17 ++ .../resolve/QualifiedExpressionResolver.kt | 7 +- .../resolve/TopDownAnalysisContext.java | 6 + .../kotlin/resolve/TypeResolutionContext.java | 13 +- .../jetbrains/kotlin/resolve/TypeResolver.kt | 280 +++++++++++++++++- .../resolve/lazy/FileScopeProviderImpl.kt | 2 +- .../resolve/lazy/LazyDeclarationResolver.java | 8 + .../AbstractPsiBasedDeclarationProvider.kt | 39 +-- ...ombinedPackageMemberDeclarationProvider.kt | 2 + .../lazy/declarations/DeclarationProvider.kt | 3 + .../descriptors/AbstractLazyMemberScope.kt | 29 +- .../descriptors/TypeAliasDescriptorImpl.kt | 111 +++++++ .../jetbrains/kotlin/resolve/scopes/Scopes.kt | 2 + .../testData/codegen/box/typealias/simple.kt | 5 + .../tests/typealias/parameterRestrictions.kt | 5 + .../tests/typealias/parameterRestrictions.txt | 6 + .../tests/typealias/parameterSubstitution.kt | 8 + .../tests/typealias/parameterSubstitution.txt | 14 + .../diagnostics/tests/typealias/recursive.kt | 4 + .../diagnostics/tests/typealias/recursive.txt | 5 + .../tests/typealias/simpleTypeAlias.kt | 8 + .../tests/typealias/simpleTypeAlias.txt | 9 + .../tests/typealias/substitutionVariance.kt | 20 ++ .../tests/typealias/substitutionVariance.txt | 36 +++ .../kotlin/test/util/DescriptorValidator.java | 14 + .../util/RecursiveDescriptorProcessor.java | 6 + .../checkers/DiagnosticsTestGenerated.java | 39 +++ .../codegen/BlackBoxCodegenTestGenerated.java | 15 + .../RecursiveDescriptorProcessorTest.java | 6 + .../kotlin/descriptors/ClassDescriptor.java | 3 +- ...lassifierDescriptorWithTypeParameters.java | 28 ++ .../DeclarationDescriptorVisitor.java | 2 + .../kotlin/descriptors/TypeAliasDescriptor.kt | 28 ++ ...clarationDescriptorVisitorEmptyBodies.java | 5 + .../kotlin/renderer/DescriptorRendererImpl.kt | 28 +- .../kotlin/types/TypeCapabilities.kt | 10 + .../org/jetbrains/kotlin/types/TypeUtils.java | 9 +- .../idea/project/ResolveElementCache.kt | 2 + .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 +- 46 files changed, 919 insertions(+), 56 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/TypeAliasDescriptorImpl.kt create mode 100644 compiler/testData/codegen/box/typealias/simple.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/parameterRestrictions.txt create mode 100644 compiler/testData/diagnostics/tests/typealias/parameterSubstitution.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/parameterSubstitution.txt create mode 100644 compiler/testData/diagnostics/tests/typealias/recursive.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/recursive.txt create mode 100644 compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.txt create mode 100644 compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt create mode 100644 compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt create mode 100644 core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassifierDescriptorWithTypeParameters.java create mode 100644 core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeAliasDescriptor.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt index 18eff93dde9..22d3614d676 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt @@ -16,8 +16,8 @@ package org.jetbrains.kotlin.cli.jvm.repl -import org.jetbrains.kotlin.resolve.lazy.declarations.PackageMemberDeclarationProvider import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.lazy.declarations.PackageMemberDeclarationProvider import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter open class DelegatePackageMemberDeclarationProvider(var delegate: PackageMemberDeclarationProvider) : PackageMemberDeclarationProvider { @@ -35,4 +35,6 @@ open class DelegatePackageMemberDeclarationProvider(var delegate: PackageMemberD override fun getPropertyDeclarations(name: Name) = delegate.getPropertyDeclarations(name) override fun getClassOrObjectDeclarations(name: Name) = delegate.getClassOrObjectDeclarations(name) + + override fun getTypeAliasDeclarations(name: Name) = delegate.getTypeAliasDeclarations(name) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index bd7c513e8c3..39a846e8e09 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -115,6 +115,11 @@ public interface Errors { DiagnosticFactory0 REIFIED_TYPE_IN_CATCH_CLAUSE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 GENERIC_THROWABLE_SUBCLASS = DiagnosticFactory0.create(ERROR); + DiagnosticFactory1 RECURSIVE_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR); + DiagnosticFactory3 UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION = + DiagnosticFactory3.create(ERROR); + DiagnosticFactory1 CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION = DiagnosticFactory1.create(ERROR); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Errors in declarations @@ -281,8 +286,8 @@ public interface Errors { DiagnosticFactory2 NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER = DiagnosticFactory2.create(ERROR); - DiagnosticFactory0 - VARIANCE_ON_TYPE_PARAMETER_OF_FUNCTION_OR_PROPERTY = DiagnosticFactory0.create(ERROR, VARIANCE_MODIFIER); + DiagnosticFactory0 VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED = DiagnosticFactory0.create(ERROR, VARIANCE_MODIFIER); + DiagnosticFactory0 BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 DEPRECATED_TYPE_PARAMETER_SYNTAX = DiagnosticFactory0.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 49a2c3edcfc..8aab750e963 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -413,6 +413,13 @@ 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(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}'': " + + "should be subtype of ''{0}'', substituted type is ''{1}''", + RENDER_TYPE, RENDER_TYPE, NAME); + MAP.put(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION, "Conflicting projection in type alias expansion in intermediate type ''{0}''", RENDER_TYPE); + MAP.put(TOO_MANY_ARGUMENTS, "Too many arguments for {0}", FQ_NAMES_IN_TYPES); MAP.put(CONSTANT_EXPECTED_TYPE_MISMATCH, "The {0} literal does not conform to the expected type {1}", STRING, RENDER_TYPE); @@ -503,7 +510,8 @@ public class DefaultErrorMessages { MAP.put(MISSING_CONSTRUCTOR_KEYWORD, "Use 'constructor' keyword after modifiers of primary constructor"); - MAP.put(VARIANCE_ON_TYPE_PARAMETER_OF_FUNCTION_OR_PROPERTY, "Variance annotations are only allowed for type parameters of classes and interfaces"); + MAP.put(VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED, "Variance annotations are only allowed for type parameters of classes and interfaces"); + MAP.put(BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED, "Bounds are not allowed on type alias parameters"); MAP.put(DEPRECATED_TYPE_PARAMETER_SYNTAX, "Type parameters must be placed before the name of the function"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 8828b88d6b1..613fc9098bf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -216,10 +216,11 @@ public interface BindingContext { WritableSlice VALUE_PARAMETER = Slices.createSimpleSlice(); WritableSlice PROPERTY_ACCESSOR = Slices.createSimpleSlice(); WritableSlice PRIMARY_CONSTRUCTOR_PARAMETER = Slices.createSimpleSlice(); + WritableSlice TYPE_ALIAS = Slices.createSimpleSlice(); WritableSlice[] DECLARATIONS_TO_DESCRIPTORS = new WritableSlice[] { CLASS, TYPE_PARAMETER, FUNCTION, CONSTRUCTOR, VARIABLE, VALUE_PARAMETER, PROPERTY_ACCESSOR, - PRIMARY_CONSTRUCTOR_PARAMETER, SCRIPT + PRIMARY_CONSTRUCTOR_PARAMETER, SCRIPT, TYPE_ALIAS }; @SuppressWarnings("unchecked") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java index df05bacbac8..d32ed4b6cd8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodiesResolveContext.java @@ -20,10 +20,7 @@ import org.jetbrains.annotations.Mutable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.ReadOnly; -import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes; -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor; -import org.jetbrains.kotlin.descriptors.PropertyDescriptor; -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor; +import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor; @@ -49,6 +46,8 @@ public interface BodiesResolveContext { Map getProperties(); @Mutable Map getFunctions(); + @Mutable + Map getTypeAliases(); @Nullable LexicalScope getDeclaringScope(@NotNull KtDeclaration declaration); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 635f2075b1e..f4418ffa5d6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory; import org.jetbrains.kotlin.resolve.dataClassUtils.DataClassUtilsKt; import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil; +import org.jetbrains.kotlin.resolve.lazy.descriptors.TypeAliasDescriptorImpl; import org.jetbrains.kotlin.resolve.scopes.*; import org.jetbrains.kotlin.resolve.scopes.utils.ScopeUtilsKt; import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt; @@ -62,6 +63,7 @@ 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.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveModalityFromModifiers; import static org.jetbrains.kotlin.resolve.ModifiersChecker.resolveVisibilityFromModifiers; @@ -388,24 +390,29 @@ public class DescriptorResolver { return builtIns.getArrayType(Variance.OUT_VARIANCE, elementType); } - public List resolveTypeParametersForCallableDescriptor( + public List resolveTypeParametersForDescriptor( DeclarationDescriptor containingDescriptor, LexicalWritableScope extensibleScope, LexicalScope scopeForAnnotationsResolve, List typeParameters, BindingTrace trace ) { + assert containingDescriptor instanceof FunctionDescriptor || + containingDescriptor instanceof PropertyDescriptor || + containingDescriptor instanceof TypeAliasDescriptor + : "This method should be called for functions, properties, or type aliases, got " + containingDescriptor; + List result = new ArrayList(); for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) { KtTypeParameter typeParameter = typeParameters.get(i); - result.add(resolveTypeParameterForCallableDescriptor( + result.add(resolveTypeParameterForDescriptor( containingDescriptor, extensibleScope, scopeForAnnotationsResolve, typeParameter, i, trace)); } return result; } - private TypeParameterDescriptorImpl resolveTypeParameterForCallableDescriptor( - DeclarationDescriptor containingDescriptor, + private TypeParameterDescriptorImpl resolveTypeParameterForDescriptor( + final DeclarationDescriptor containingDescriptor, LexicalWritableScope extensibleScope, LexicalScope scopeForAnnotationsResolve, final KtTypeParameter typeParameter, @@ -413,8 +420,7 @@ public class DescriptorResolver { final BindingTrace trace ) { if (typeParameter.getVariance() != Variance.INVARIANT) { - assert !(containingDescriptor instanceof ClassifierDescriptor) : "This method is intended for functions/properties"; - trace.report(VARIANCE_ON_TYPE_PARAMETER_OF_FUNCTION_OR_PROPERTY.on(typeParameter)); + trace.report(VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED.on(typeParameter)); } Annotations annotations = @@ -431,7 +437,9 @@ public class DescriptorResolver { new Function1() { @Override public Void invoke(KotlinType type) { - trace.report(Errors.CYCLIC_GENERIC_UPPER_BOUND.on(typeParameter)); + if (!(containingDescriptor instanceof TypeAliasDescriptor)) { + trace.report(Errors.CYCLIC_GENERIC_UPPER_BOUND.on(typeParameter)); + } return null; } }, @@ -667,6 +675,65 @@ public class DescriptorResolver { return variableDescriptor; } + @NotNull + public TypeAliasDescriptor resolveTypeAliasDescriptor( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull LexicalScope scope, + @NotNull KtTypeAlias typeAlias, + @NotNull final BindingTrace trace + ) { + 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); + TypeAliasDescriptorImpl typeAliasDescriptor = TypeAliasDescriptorImpl.create( + containingDeclaration, allAnnotations, name, sourceElement, visibility); + + List typeParameterDescriptors; + final LexicalScope scopeWithTypeParameters; + { + List typeParameters = typeAlias.getTypeParameters(); + if (typeParameters.isEmpty()) { + scopeWithTypeParameters = scope; + typeParameterDescriptors = Collections.emptyList(); + } + else { + LexicalWritableScope writableScope = new LexicalWritableScope( + scope, containingDeclaration, false, null, new TraceBasedLocalRedeclarationChecker(trace), + LexicalScopeKind.TYPE_ALIAS_HEADER); + typeParameterDescriptors = resolveTypeParametersForDescriptor( + typeAliasDescriptor, writableScope, scope, typeParameters, trace); + writableScope.freeze(); + checkNoGenericBoundsOnTypeAliasParameters(typeAlias, trace); + resolveGenericBounds(typeAlias, typeAliasDescriptor, writableScope, typeParameterDescriptors, trace); + scopeWithTypeParameters = writableScope; + } + } + + final KtTypeReference typeReference = typeAlias.getTypeReference(); + + typeAliasDescriptor.initialize(typeParameterDescriptors, storageManager.createLazyValue(new Function0() { + @Override + public KotlinType invoke() { + return typeResolver.resolveAbbreviatedType(scopeWithTypeParameters, typeReference, trace, true); + } + })); + + trace.record(TYPE_ALIAS, typeAlias, typeAliasDescriptor); + return typeAliasDescriptor; + } + + private static void checkNoGenericBoundsOnTypeAliasParameters(@NotNull KtTypeAlias typeAlias, @NotNull BindingTrace trace) { + for (KtTypeParameter typeParameter : typeAlias.getTypeParameters()) { + KtTypeReference bound = typeParameter.getExtendsBound(); + if (bound != null) { + trace.report(BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED.on(bound)); + } + } + } + @NotNull public PropertyDescriptor resolvePropertyDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @@ -727,7 +794,7 @@ public class DescriptorResolver { LexicalWritableScope writableScope = new LexicalWritableScope( scope, containingDeclaration, false, null, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker), LexicalScopeKind.PROPERTY_HEADER); - typeParameterDescriptors = resolveTypeParametersForCallableDescriptor( + typeParameterDescriptors = resolveTypeParametersForDescriptor( propertyDescriptor, writableScope, scope, typeParameters, trace); writableScope.freeze(); resolveGenericBounds(property, propertyDescriptor, writableScope, typeParameterDescriptors, trace); @@ -1092,6 +1159,27 @@ public class DescriptorResolver { } } + public static void checkBoundsInTypeAlias( + @NotNull KtUserType typeAliasElement, + @NotNull KotlinType typeArgument, + @NotNull TypeParameterDescriptor typeParameterDescriptor, + @NotNull TypeSubstitutor substitutor, + @NotNull BindingTrace trace + ) { + 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)); + } + } + } + public static boolean checkHasOuterClassInstance( @NotNull LexicalScope scope, @NotNull BindingTrace trace, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt index ec3fc919d3b..bca93c1367c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionDescriptorResolver.kt @@ -146,7 +146,7 @@ class FunctionDescriptorResolver( TraceBasedLocalRedeclarationChecker(trace, overloadChecker), LexicalScopeKind.FUNCTION_HEADER) val typeParameterDescriptors = descriptorResolver. - resolveTypeParametersForCallableDescriptor(functionDescriptor, innerScope, scope, function.typeParameters, trace) + resolveTypeParametersForDescriptor(functionDescriptor, innerScope, scope, function.typeParameters, trace) descriptorResolver.resolveGenericBounds(function, functionDescriptor, innerScope, typeParameterDescriptors, trace) val receiverTypeRef = function.receiverTypeReference diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt index 5dbfa46f930..3f84249a2a0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt @@ -54,6 +54,7 @@ class LazyTopDownAnalyzer( val properties = ArrayList() val functions = ArrayList() + val typeAliases = ArrayList() // fill in the context for (declaration in declarations) { @@ -168,6 +169,10 @@ class LazyTopDownAnalyzer( override fun visitProperty(property: KtProperty) { properties.add(property) } + + override fun visitTypeAlias(typeAlias: KtTypeAlias) { + typeAliases.add(typeAlias) + } }) } @@ -175,6 +180,8 @@ class LazyTopDownAnalyzer( createPropertyDescriptors(c, topLevelFqNames, properties) + createTypeAliasDescriptors(c, topLevelFqNames, typeAliases) + resolveAllHeadersInClasses(c) declarationResolver.checkRedeclarationsInPackages(topLevelDescriptorProvider, topLevelFqNames) @@ -199,6 +206,16 @@ class LazyTopDownAnalyzer( } } + private fun createTypeAliasDescriptors(c: TopDownAnalysisContext, topLevelFqNames: Multimap, typeAliases: List) { + for (typeAlias in typeAliases) { + val descriptor = lazyDeclarationResolver.resolveToDescriptor(typeAlias) as TypeAliasDescriptor + + c.typeAliases[typeAlias] = descriptor + ForceResolveUtil.forceResolveAllContents(descriptor.annotations) + registerTopLevelFqName(topLevelFqNames, typeAlias, descriptor) + } + } + private fun createPropertyDescriptors(c: TopDownAnalysisContext, topLevelFqNames: Multimap, properties: List) { for (property in properties) { val descriptor = lazyDeclarationResolver.resolveToDescriptor(property) as PropertyDescriptor diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index 40b2fb0c122..e795612c243 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -370,8 +370,10 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator val nextPackageOrClassDescriptor = when (currentDescriptor) { + is TypeAliasDescriptor -> // TODO type aliases as qualifiers? (would break some assumptions in TypeResolver) + currentDescriptor.underlyingClassDescriptor.getContributedClassifier(qualifierPart) is ClassDescriptor -> - currentDescriptor.unsubstitutedInnerClassesScope.getContributedClassifier(qualifierPart.name, qualifierPart.location) + currentDescriptor.getContributedClassifier(qualifierPart) is PackageViewDescriptor -> { val packageView = if (qualifierPart.typeArguments == null) { @@ -404,6 +406,9 @@ class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator return Pair(currentDescriptor, path.size) } + fun ClassDescriptor.getContributedClassifier(qualifierPart: QualifierPart) = + unsubstitutedInnerClassesScope.getContributedClassifier(qualifierPart.name, qualifierPart.location) + fun resolveNameExpressionAsQualifierForDiagnostics( expression: KtSimpleNameExpression, receiver: Receiver?, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java index 1bc92ab6d09..3826ac90b90 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TopDownAnalysisContext.java @@ -45,6 +45,7 @@ public class TopDownAnalysisContext implements BodiesResolveContext { private final Map functions = Maps.newLinkedHashMap(); private final Map properties = Maps.newLinkedHashMap(); private final Map primaryConstructorParameterProperties = Maps.newHashMap(); + private final Map typeAliases = Maps.newLinkedHashMap(); private Map members = null; private final Map scripts = Maps.newLinkedHashMap(); @@ -139,6 +140,11 @@ public class TopDownAnalysisContext implements BodiesResolveContext { return functions; } + @Override + public Map getTypeAliases() { + return typeAliases; + } + @NotNull public Map getMembers() { if (members == null) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java index 7b4c5d2db21..9e2e7e4bbdf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolutionContext.java @@ -26,9 +26,14 @@ public class TypeResolutionContext { public final boolean allowBareTypes; public final boolean forceResolveLazyTypes; public final boolean isDebuggerContext; + public final boolean abbreviated; public TypeResolutionContext(@NotNull LexicalScope scope, @NotNull BindingTrace trace, boolean checkBounds, boolean allowBareTypes, boolean isDebuggerContext) { - this(scope, trace, checkBounds, allowBareTypes, allowBareTypes, isDebuggerContext); + this(scope, trace, checkBounds, allowBareTypes, allowBareTypes, isDebuggerContext, false); + } + + public TypeResolutionContext(@NotNull LexicalScope scope, @NotNull BindingTrace trace, boolean checkBounds, boolean allowBareTypes, boolean isDebuggerContext, boolean abbreviated) { + this(scope, trace, checkBounds, allowBareTypes, allowBareTypes, isDebuggerContext, abbreviated); } private TypeResolutionContext( @@ -37,7 +42,8 @@ public class TypeResolutionContext { boolean checkBounds, boolean allowBareTypes, boolean forceResolveLazyTypes, - boolean isDebuggerContext + boolean isDebuggerContext, + boolean abbreviated ) { this.scope = scope; this.trace = trace; @@ -45,9 +51,10 @@ public class TypeResolutionContext { this.allowBareTypes = allowBareTypes; this.forceResolveLazyTypes = forceResolveLazyTypes; this.isDebuggerContext = isDebuggerContext; + this.abbreviated = abbreviated; } public TypeResolutionContext noBareTypes() { - return new TypeResolutionContext(scope, trace, checkBounds, false, forceResolveLazyTypes, isDebuggerContext); + return new TypeResolutionContext(scope, trace, checkBounds, false, forceResolveLazyTypes, isDebuggerContext, abbreviated); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index aa7363c9407..ef79bf82e4e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.Variance.* import org.jetbrains.kotlin.types.typeUtil.isArrayOfNothing +import java.util.* class TypeResolver( private val annotationResolver: AnnotationResolver, @@ -64,7 +65,11 @@ class TypeResolver( fun resolveType(scope: LexicalScope, typeReference: KtTypeReference, trace: BindingTrace, checkBounds: Boolean): KotlinType { // bare types are not allowed - return resolveType(TypeResolutionContext(scope, trace, checkBounds, false, typeReference.suppressDiagnosticsInDebugMode()), typeReference) + return resolveType(TypeResolutionContext(scope, trace, checkBounds, false, typeReference.suppressDiagnosticsInDebugMode(), false), typeReference) + } + + fun resolveAbbreviatedType(scope: LexicalScope, typeReference: KtTypeReference, trace: BindingTrace, checkBounds: Boolean): KotlinType { + return resolveType(TypeResolutionContext(scope, trace, checkBounds, false, typeReference.suppressDiagnosticsInDebugMode(), true), typeReference) } private fun resolveType(c: TypeResolutionContext, typeReference: KtTypeReference): KotlinType { @@ -181,7 +186,10 @@ class TypeResolver( type(resolveTypeForTypeParameter(c, annotations, classifierDescriptor, referenceExpression, type)) } - is ClassDescriptor -> resolveTypeForClass(c, annotations, classifierDescriptor, type, qualifierResolutionResults) + is ClassDescriptor -> + resolveTypeForClass(c, annotations, classifierDescriptor, type, qualifierResolutionResults) + is TypeAliasDescriptor -> + resolveTypeForTypeAlias(c, annotations, classifierDescriptor, type, qualifierResolutionResults) else -> error("Unexpected classifier type: ${classifierDescriptor.javaClass}") } } @@ -347,7 +355,7 @@ class TypeResolver( } if (ErrorUtils.isError(classDescriptor)) { - return createErrorTypeAndResolveArguments(c, projectionFromAllQualifierParts, "[Error type: $typeConstructor]") + return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeConstructor) } val collectedArgumentAsTypeProjections = @@ -393,6 +401,264 @@ class TypeResolver( return type(resultingType) } + private fun resolveTypeForTypeAlias( + c: TypeResolutionContext, + annotations: Annotations, + typeAliasDescriptor: TypeAliasDescriptor, + type: KtUserType, + qualifierResolutionResult: QualifiedExpressionResolver.TypeQualifierResolutionResult + ): PossiblyBareType { + val typeAliasConstructor = typeAliasDescriptor.typeConstructor + val projectionFromAllQualifierParts = qualifierResolutionResult.allProjections + + if (ErrorUtils.isError(typeAliasDescriptor)) { + return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeAliasConstructor) + } + + // TODO type arguments substitution for type parameters of outer classes + // TODO should we support type aliases as qualifiers? what about generics? + + val typeAliasParameters = typeAliasDescriptor.declaredTypeParameters + + val typeAliasQualifierPart = qualifierResolutionResult.qualifierParts.lastOrNull() + ?: return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeAliasConstructor) + + // TODO appendDefaultArgumentsForInnerScope + val typeAliasArguments = typeAliasQualifierPart.typeArguments?.arguments.orEmpty() + + if (typeAliasParameters.size != typeAliasArguments.size) { + c.trace.report(WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(typeAliasQualifierPart.typeArguments ?: typeAliasQualifierPart.expression, + typeAliasParameters.size, typeAliasDescriptor)) + return createErrorTypeForTypeConstructor(c, projectionFromAllQualifierParts, typeAliasConstructor) + } + + return if (c.abbreviated) { + val arguments = resolveTypeProjections(c, typeAliasDescriptor.typeConstructor, typeAliasArguments) + val abbreviatedType = KotlinTypeImpl.create(annotations, typeAliasDescriptor.typeConstructor, false, arguments, MemberScope.Empty) + type(abbreviatedType) + } + else { + val typeAliasExpansion = createTypeAliasExpansionFromSource(c, type, typeAliasDescriptor, typeAliasArguments) + val expandedType = expandTypeAlias(c, typeAliasExpansion, annotations) + type(expandedType) + } + } + + 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 class TypeAliasExpansion( + val context: TypeAliasExpansionContext, + val parent: TypeAliasExpansion?, + val descriptor: TypeAliasDescriptor, + val arguments: List, + val mapping: Map + ) { + fun getReplacement(constructor: TypeConstructor): TypeProjection? { + val descriptor = constructor.declarationDescriptor + return if (descriptor is TypeParameterDescriptor) + mapping[descriptor] + else + null + } + + fun isRecursion(descriptor: TypeAliasDescriptor): Boolean = + 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, + typeAliasDescriptor: TypeAliasDescriptor, + expandedArguments: List + ): TypeAliasExpansion { + val mappedArguments = HashMap() + typeAliasDescriptor.typeConstructor.parameters.forEachIndexed { i, typeParameterDescriptor -> + mappedArguments[typeParameterDescriptor] = expandedArguments[i] + } + + return TypeAliasExpansion(parent.context, parent, typeAliasDescriptor, expandedArguments, mappedArguments) + } + + private fun expandTypeAlias( + c: TypeResolutionContext, + typeAliasExpansion: TypeAliasExpansion, + annotations: Annotations + ): KotlinType { + val originalProjection = TypeProjectionImpl(Variance.INVARIANT, typeAliasExpansion.descriptor.underlyingType) + val expandedProjection = expandTypeProjectionForTypeAlias(c, originalProjection, typeAliasExpansion, null, 1) + + if (expandedProjection.type.isError) return expandedProjection.type + + assert(expandedProjection.projectionKind == Variance.INVARIANT) { + "Type alias expansion: result for ${typeAliasExpansion.descriptor} is ${expandedProjection.projectionKind}, should be invariant" + } + + val abbreviatedType = KotlinTypeImpl.create(annotations, typeAliasExpansion.descriptor.typeConstructor, + originalProjection.type.isMarkedNullable, + typeAliasExpansion.arguments, MemberScope.Empty) + + return expandedProjection.type.replace( + newAnnotations = annotations, + newCapabilities = withAbbreviatedType(abbreviatedType)) + } + + private fun expandTypeProjectionForTypeAlias( + c: TypeResolutionContext, + originalProjection: TypeProjection, + typeAliasExpansion: TypeAliasExpansion, + typeParameterDescriptor: TypeParameterDescriptor?, + recursionDepth: Int + ): TypeProjection { + assertRecursionDepth(recursionDepth) { + "Too deep recursion while expanding type alias ${typeAliasExpansion.descriptor}" + } + + val originalType = originalProjection.type + + val typeAliasArgument = typeAliasExpansion.getReplacement(originalType.constructor) + + if (typeAliasArgument == null) { + return substituteNonArgumentTypeForTypeAlias(c, originalProjection, typeAliasExpansion, recursionDepth) + } + + val originalVariance = + if (originalProjection.projectionKind != Variance.INVARIANT) + originalProjection.projectionKind + else if (typeParameterDescriptor != null) + typeParameterDescriptor.variance + else + Variance.INVARIANT + + val argumentVariance = typeAliasArgument.projectionKind + + val substitutedVariance = + if (argumentVariance == Variance.INVARIANT) + originalVariance + else if (originalVariance == Variance.INVARIANT || originalVariance == argumentVariance) + argumentVariance + else if (typeAliasArgument.isStarProjection) + 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)) + } + } + argumentVariance + } + + val substitutedType = TypeUtils.makeNullableIfNeeded(typeAliasArgument.type, originalType.isMarkedNullable) + + return TypeProjectionImpl(substitutedVariance, substitutedType) + } + + private fun substituteNonArgumentTypeForTypeAlias( + c: TypeResolutionContext, + originalProjection: TypeProjection, + typeAliasExpansion: TypeAliasExpansion, + recursionDepth: Int + ): TypeProjection { + val type = originalProjection.type + val typeConstructor = type.constructor + val typeDescriptor = typeConstructor.declarationDescriptor + + when (typeDescriptor) { + is TypeParameterDescriptor -> { + return originalProjection + } + is TypeAliasDescriptor -> { + if (typeAliasExpansion.isRecursion(typeDescriptor)) { + c.trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(typeAliasExpansion.context.element, 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) + } + + val nestedExpansion = createNestedTypeAliasExpansion(typeAliasExpansion, typeDescriptor, expandedArguments) + + val expandedType = expandTypeAlias(c, nestedExpansion, type.annotations) + + return TypeProjectionImpl(originalProjection.projectionKind, + if (expandedType.isError) expandedType else expandedType.replace(newCapabilities = withAbbreviatedType(type))) + } + else -> { + val substitutedArguments = type.arguments.mapIndexed { i, originalArgument -> + expandTypeProjectionForTypeAlias(c, originalArgument, typeAliasExpansion, typeConstructor.parameters[i], recursionDepth + 1) + } + + checkTypeArgumentsSubstitutionInTypeAliasExpansion(c, type, substitutedArguments, typeAliasExpansion) + + val substitutedType = type.replace(newArguments = substitutedArguments) + + return TypeProjectionImpl(originalProjection.projectionKind, substitutedType) + } + } + } + + private fun checkTypeArgumentsSubstitutionInTypeAliasExpansion( + c: TypeResolutionContext, + type: KotlinType, + substitutedArguments: List, + typeAliasExpansion: TypeAliasExpansion + ) { + 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) + } + } + + private fun createErrorTypeForTypeConstructor( + c: TypeResolutionContext, + arguments: List, + typeConstructor: TypeConstructor + ) = + createErrorTypeAndResolveArguments(c, arguments, "[Error type: $typeConstructor]") + // 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 // from enclosing functions. In such cases you can not specify any argument: @@ -583,6 +849,14 @@ class TypeResolver( } companion object { + private const val MAX_RECURSION_DEPTH = 100 + + private inline fun assertRecursionDepth(recursionDepth: Int, lazyMessage: () -> String) { + if (recursionDepth > MAX_RECURSION_DEPTH) { + throw AssertionError(lazyMessage()) + } + } + @JvmStatic fun resolveProjectionKind(projectionKind: KtProjectionKind): Variance { return when (projectionKind) { KtProjectionKind.IN -> IN_VARIANCE diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt index 5ab36f76236..101e5b59538 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeProviderImpl.kt @@ -160,7 +160,7 @@ open class FileScopeProviderImpl( override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { if (name in excludedNames) return null val classifier = scope.getContributedClassifier(name, location) ?: return null - val visible = Visibilities.isVisibleIgnoringReceiver(classifier as ClassDescriptor, fromDescriptor) + val visible = Visibilities.isVisibleIgnoringReceiver(classifier as DeclarationDescriptorWithVisibility, fromDescriptor) return classifier.check { filteringKind == if (visible) FilteringKind.VISIBLE_CLASSES else FilteringKind.INVISIBLE_CLASSES } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java index 11e5f94d797..b6524c05cf7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyDeclarationResolver.java @@ -224,6 +224,14 @@ public class LazyDeclarationResolver { return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property); } + @Override + public DeclarationDescriptor visitTypeAlias(@NotNull KtTypeAlias typeAlias, Void data) { + LookupLocation location = lookupLocationFor(typeAlias, typeAlias.isTopLevel()); + MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(typeAlias, location); + scopeForDeclaration.getContributedClassifier(typeAlias.getNameAsSafeName(), location); + return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, typeAlias); + } + @Override public DeclarationDescriptor visitScript(@NotNull KtScript script, Void data) { return getScriptDescriptor(script, lookupLocationFor(script, true)); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt index 2e4d1f91781..2881eb2722d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/AbstractPsiBasedDeclarationProvider.kt @@ -36,29 +36,29 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage val functions = ArrayListMultimap.create() val properties = ArrayListMultimap.create() val classesAndObjects = ArrayListMultimap.create() // order matters here + val typeAliases = ArrayListMultimap.create() fun putToIndex(declaration: KtDeclaration) { if (declaration is KtAnonymousInitializer || declaration is KtSecondaryConstructor) return allDeclarations.add(declaration) - if (declaration is KtNamedFunction) { - functions.put(safeNameForLazyResolve(declaration), declaration) - } - else if (declaration is KtProperty) { - properties.put(safeNameForLazyResolve(declaration), declaration) - } - else if (declaration is KtClassOrObject) { - classesAndObjects.put(safeNameForLazyResolve(declaration.getNameAsName()), KtClassInfoUtil.createClassLikeInfo(declaration)) - } - else if (declaration is KtScript) { - val scriptInfo = KtScriptInfo(declaration) - classesAndObjects.put(scriptInfo.script.nameAsName, scriptInfo) - } - else if (declaration is KtParameter || declaration is KtDestructuringDeclaration) { - // Do nothing, just put it into allDeclarations is enough - } - else { - throw IllegalArgumentException("Unknown declaration: " + declaration) + when (declaration) { + is KtNamedFunction -> + functions.put(safeNameForLazyResolve(declaration), declaration) + is KtProperty -> + properties.put(safeNameForLazyResolve(declaration), declaration) + is KtTypeAlias -> + typeAliases.put(safeNameForLazyResolve(declaration.nameAsName), declaration) + is KtClassOrObject -> + classesAndObjects.put(safeNameForLazyResolve(declaration.nameAsName), KtClassInfoUtil.createClassLikeInfo(declaration)) + is KtScript -> { + val scriptInfo = KtScriptInfo(declaration) + classesAndObjects.put(scriptInfo.script.nameAsName, scriptInfo) + } + is KtParameter, is KtDestructuringDeclaration -> { + // Do nothing, just put it into allDeclarations is enough + } + else -> throw IllegalArgumentException("Unknown declaration: " + declaration) } } } @@ -82,4 +82,7 @@ abstract class AbstractPsiBasedDeclarationProvider(storageManager: StorageManage override fun getClassOrObjectDeclarations(name: Name): Collection = index().classesAndObjects[ResolveSessionUtils.safeNameForLazyResolve(name)] + + override fun getTypeAliasDeclarations(name: Name): Collection + = index().typeAliases[ResolveSessionUtils.safeNameForLazyResolve(name)] } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt index d9070fab89b..daae17a2155 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt @@ -32,4 +32,6 @@ class CombinedPackageMemberDeclarationProvider(val providers: Collection fun getClassOrObjectDeclarations(name: Name): Collection + + fun getTypeAliasDeclarations(name: Name): Collection } 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 41213bd0442..5e2cb7ad342 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 @@ -50,6 +50,7 @@ protected constructor( private val classDescriptors: MemoizedFunctionToNotNull> = storageManager.createMemoizedFunction { resolveClassDescriptor(it) } private val functionDescriptors: MemoizedFunctionToNotNull> = storageManager.createMemoizedFunction { doGetFunctions(it) } private val propertyDescriptors: MemoizedFunctionToNotNull> = storageManager.createMemoizedFunction { doGetProperties(it) } + private val typeAliasDescriptors: MemoizedFunctionToNotNull> = storageManager.createMemoizedFunction { doGetTypeAliases(it) } private fun resolveClassDescriptor(name: Name): List { return declarationProvider.getClassOrObjectDeclarations(name).map { @@ -60,9 +61,9 @@ protected constructor( }.toReadOnlyList() } - override fun getContributedClassifier(name: Name, location: LookupLocation): ClassDescriptor? { + override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? { recordLookup(name, location) - return classDescriptors(name).firstOrNull() + return classDescriptors(name).firstOrNull() ?: typeAliasDescriptors(name).firstOrNull() } override fun getContributedFunctions(name: Name, location: LookupLocation): Collection { @@ -120,6 +121,20 @@ protected constructor( protected abstract fun getNonDeclaredProperties(name: Name, result: MutableSet) + protected fun getContributedTypeAliasDescriptors(name: Name, location: LookupLocation): Collection { + recordLookup(name, location) + return typeAliasDescriptors(name) + } + + private fun doGetTypeAliases(name: Name): Collection = + declarationProvider.getTypeAliasDeclarations(name).map { ktTypeAlias -> + c.descriptorResolver.resolveTypeAliasDescriptor( + thisDescriptor, + getScopeForMemberDeclarationResolution(ktTypeAlias), + ktTypeAlias, + trace) + }.toReadOnlyList() + protected fun computeDescriptorsFromDeclaredElements( kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, @@ -152,6 +167,12 @@ protected constructor( result.addAll(getContributedVariables(name, location)) } } + else if (declaration is KtTypeAlias) { + val name = declaration.nameAsSafeName + if (nameFilter(name)) { + result.addAll(getContributedTypeAliasDescriptors(name, location)) + } + } else if (declaration is KtScript) { val name = declaration.nameAsSafeName if (nameFilter(name)) { @@ -161,9 +182,7 @@ protected constructor( else if (declaration is KtDestructuringDeclaration) { // MultiDeclarations are not supported on global level } - else { - throw IllegalArgumentException("Unsupported declaration kind: " + declaration) - } + else throw IllegalArgumentException("Unsupported declaration kind: " + declaration) } return result.toReadOnlyList() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/TypeAliasDescriptorImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/TypeAliasDescriptorImpl.kt new file mode 100644 index 00000000000..4d7e3a604a2 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/TypeAliasDescriptorImpl.kt @@ -0,0 +1,111 @@ +/* + * 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.lazy.descriptors + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorNonRootImpl +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtTypeReference +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.storage.NotNullLazyValue +import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeConstructor +import org.jetbrains.kotlin.types.TypeSubstitutor + +class TypeAliasDescriptorImpl( + containingDeclaration: DeclarationDescriptor, + annotations: Annotations, + name: Name, + sourceElement: SourceElement, + private val fVisibility: Visibility +) : DeclarationDescriptorNonRootImpl(containingDeclaration, annotations, name, sourceElement), + TypeAliasDescriptor { + + // TODO kotlinize some interfaces + private lateinit var fDeclaredTypeParameters: List + private lateinit var lazyUnderlyingType: NotNullLazyValue + + override val underlyingType: KotlinType get() = lazyUnderlyingType() + + fun initialize(declaredTypeParameters: List, lazyUnderlyingType: NotNullLazyValue) { + this.fDeclaredTypeParameters = declaredTypeParameters + this.lazyUnderlyingType = lazyUnderlyingType + } + + override fun accept(visitor: DeclarationDescriptorVisitor, data: D): R = + visitor.visitTypeAliasDescriptor(this, data) + + override fun getDeclaredTypeParameters(): List = + fDeclaredTypeParameters + + override val underlyingClassDescriptor: ClassDescriptor + get() = underlyingType.constructor.declarationDescriptor as ClassDescriptor // TODO + + override fun getModality() = Modality.FINAL + + override fun getVisibility() = fVisibility + + override fun substitute(substitutor: TypeSubstitutor): TypeAliasDescriptor = + if (substitutor.isEmpty) this + else TODO("typealias doSubstitute") + + override fun getDefaultType(): KotlinType = + TODO("typealias getDefaultType") + + override fun getTypeConstructor(): TypeConstructor = + typeConstructor + + override fun toString(): String = "typealias ${name.asString()}" + + private val typeConstructor = object : TypeConstructor { + override fun getDeclarationDescriptor(): TypeAliasDescriptor = + this@TypeAliasDescriptorImpl + + override fun getParameters(): List = + declarationDescriptor.declaredTypeParameters // TODO type parameters of outer class + + override fun getSupertypes(): Collection = + declarationDescriptor.underlyingType.constructor.supertypes + + override fun isFinal(): Boolean = + declarationDescriptor.underlyingType.constructor.isFinal + + override fun isDenotable(): Boolean = + true + + override fun getBuiltIns(): KotlinBuiltIns = + declarationDescriptor.builtIns + + override fun getAnnotations(): Annotations = + declarationDescriptor.annotations + } + + companion object { + @JvmStatic fun create( + containingDeclaration: DeclarationDescriptor, + annotations: Annotations, + name: Name, + sourceElement: SourceElement, + visibility: Visibility + ): TypeAliasDescriptorImpl = + TypeAliasDescriptorImpl(containingDeclaration, annotations, name, sourceElement, visibility) + } +} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt index fa2a474174d..771674cb889 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/scopes/Scopes.kt @@ -73,6 +73,8 @@ enum class LexicalScopeKind(val withLocalDescriptors: Boolean) { FUNCTION_HEADER(false), FUNCTION_INNER_SCOPE(true), + TYPE_ALIAS_HEADER(false), + CODE_BLOCK(true), LEFT_BOOLEAN_EXPRESSION(true), diff --git a/compiler/testData/codegen/box/typealias/simple.kt b/compiler/testData/codegen/box/typealias/simple.kt new file mode 100644 index 00000000000..4eb3d1b3745 --- /dev/null +++ b/compiler/testData/codegen/box/typealias/simple.kt @@ -0,0 +1,5 @@ +typealias S = String + +val OK: S = "OK" + +fun box(): S = OK diff --git a/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt b/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt new file mode 100644 index 00000000000..47d92ce185f --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt @@ -0,0 +1,5 @@ +typealias WithVariance<in X, out Y> = Int +typealias WithBounds1T> = Int +typealias WithBounds2Y, Y : X> = Int + +val x: WithVariance = 0 diff --git a/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.txt b/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.txt new file mode 100644 index 00000000000..43a814e1fbd --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/parameterRestrictions.txt @@ -0,0 +1,6 @@ +package + +public val x: WithVariance [= kotlin.Int] = 0 +public typealias WithBounds1 = kotlin.Int +public typealias WithBounds2 = kotlin.Int +public typealias WithVariance = kotlin.Int diff --git a/compiler/testData/diagnostics/tests/typealias/parameterSubstitution.kt b/compiler/testData/diagnostics/tests/typealias/parameterSubstitution.kt new file mode 100644 index 00000000000..9ea1077516a --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/parameterSubstitution.kt @@ -0,0 +1,8 @@ +class C + +typealias CA = C + +val ca1: CA = C() +val ca2: CA> = C>() +val ca3: CA> = C>() +val ca4: CA = C() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/parameterSubstitution.txt b/compiler/testData/diagnostics/tests/typealias/parameterSubstitution.txt new file mode 100644 index 00000000000..5ff4bff9708 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/parameterSubstitution.txt @@ -0,0 +1,14 @@ +package + +public val ca1: CA [= C] +public val ca2: CA [= C]> [= C [= C]>] +public val ca3: CA> [= C>] +public val ca4: CA [= C] + +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 typealias CA = C diff --git a/compiler/testData/diagnostics/tests/typealias/recursive.kt b/compiler/testData/diagnostics/tests/typealias/recursive.kt new file mode 100644 index 00000000000..d64150b2e15 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/recursive.kt @@ -0,0 +1,4 @@ +typealias A = B +typealias B = A + +val x: A = TODO() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/recursive.txt b/compiler/testData/diagnostics/tests/typealias/recursive.txt new file mode 100644 index 00000000000..09be8069705 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/recursive.txt @@ -0,0 +1,5 @@ +package + +public val x: [ERROR : Recursive type alias: A] +public typealias A = B +public typealias B = A diff --git a/compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.kt b/compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.kt new file mode 100644 index 00000000000..85ff5798030 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.kt @@ -0,0 +1,8 @@ +typealias S = String +typealias SS = S +typealias SSS = SS + +val s1: SSS = "" +val s2: SSS? = null +val s3: List? = null +val s4: List?>? = null \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.txt b/compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.txt new file mode 100644 index 00000000000..ad97eb6a586 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.txt @@ -0,0 +1,9 @@ +package + +public val s1: SSS [= kotlin.String] = "" +public val s2: SSS [= kotlin.String?] = null +public val s3: kotlin.collections.List? = null +public val s4: kotlin.collections.List?>? = null +public typealias S = kotlin.String +public typealias SS = S +public typealias SSS = SS diff --git a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt new file mode 100644 index 00000000000..1b355a97f89 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt @@ -0,0 +1,20 @@ +class In +class Out +class Inv + +typealias In1 = In +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 Out4 = Out<*> + +typealias Inv1 = Inv +typealias Inv2 = Inv +typealias Inv3 = Inv +typealias Inv4 = Inv<*> + +val inv1: Inv1 = Inv() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt new file mode 100644 index 00000000000..e4706f06e54 --- /dev/null +++ b/compiler/testData/diagnostics/tests/typealias/substitutionVariance.txt @@ -0,0 +1,36 @@ +package + +public val inv1: Inv1 [= Inv] + +public final class In { + public constructor In() + 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 Inv { + public constructor Inv() + 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 Out { + public constructor Out() + 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 typealias In1 = In +public typealias In2 = In +public typealias In3 = In +public typealias In4 = In<*> +public typealias Inv1 = Inv +public typealias Inv2 = Inv +public typealias Inv3 = Inv +public typealias Inv4 = Inv<*> +public typealias Out1 = Out +public typealias Out2 = Out +public typealias Out3 = Out +public typealias Out4 = Out<*> diff --git a/compiler/tests-common/org/jetbrains/kotlin/test/util/DescriptorValidator.java b/compiler/tests-common/org/jetbrains/kotlin/test/util/DescriptorValidator.java index bf8fde0def3..d4aeb125b7d 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/test/util/DescriptorValidator.java +++ b/compiler/tests-common/org/jetbrains/kotlin/test/util/DescriptorValidator.java @@ -273,6 +273,14 @@ public class DescriptorValidator { return true; } + @Override + public Boolean visitTypeAliasDescriptor( + TypeAliasDescriptor descriptor, DiagnosticCollector data + ) { + // TODO typealias + return true; + } + @Override public Boolean visitModuleDeclaration( ModuleDescriptor descriptor, DiagnosticCollector collector @@ -436,6 +444,12 @@ public class DescriptorValidator { return null; } + @Override + public Void visitTypeAliasDescriptor(TypeAliasDescriptor descriptor, MemberScope data) { + // TODO typealias + return null; + } + @Override public Void visitModuleDeclaration( ModuleDescriptor descriptor, MemberScope scope diff --git a/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessor.java b/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessor.java index f4f760bcc37..bde8834ed11 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessor.java +++ b/compiler/tests-common/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessor.java @@ -109,6 +109,12 @@ public class RecursiveDescriptorProcessor { && visitChildren(DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope()), data); } + @Override + public Boolean visitTypeAliasDescriptor(TypeAliasDescriptor descriptor, D data) { + // TODO typealias + return true; + } + @Override public Boolean visitModuleDeclaration(ModuleDescriptor descriptor, D data) { return applyWorker(descriptor, data) diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index c1cc571e58e..352bc63f5e6 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -19012,6 +19012,45 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/typealias") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Typealias extends AbstractDiagnosticsTest { + public void testAllFilesPresentInTypealias() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/typealias"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("parameterRestrictions.kt") + public void testParameterRestrictions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/parameterRestrictions.kt"); + doTest(fileName); + } + + @TestMetadata("parameterSubstitution.kt") + public void testParameterSubstitution() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/parameterSubstitution.kt"); + doTest(fileName); + } + + @TestMetadata("recursive.kt") + public void testRecursive() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/recursive.kt"); + doTest(fileName); + } + + @TestMetadata("simpleTypeAlias.kt") + public void testSimpleTypeAlias() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/simpleTypeAlias.kt"); + doTest(fileName); + } + + @TestMetadata("substitutionVariance.kt") + public void testSubstitutionVariance() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/typealias/substitutionVariance.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/unit") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index d926647934c..b71bc189b52 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -14321,6 +14321,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/typealias") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Typealias extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInTypealias() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/typealias"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/typealias/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/unaryOp") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessorTest.java b/compiler/tests/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessorTest.java index 7f3978865d3..4b6415406a8 100644 --- a/compiler/tests/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessorTest.java +++ b/compiler/tests/org/jetbrains/kotlin/test/util/RecursiveDescriptorProcessorTest.java @@ -129,6 +129,12 @@ public class RecursiveDescriptorProcessorTest extends KotlinTestWithEnvironment return true; } + @Override + public Boolean visitTypeAliasDescriptor(TypeAliasDescriptor descriptor, Void data) { + add(descriptor); // TODO typealias + return null; + } + @Override public Boolean visitModuleDeclaration(ModuleDescriptor descriptor, Void data) { add(descriptor); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassDescriptor.java index 0e5cae9e0a5..73cbd8b283a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassDescriptor.java @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.types.TypeSubstitutor; import java.util.Collection; import java.util.List; -public interface ClassDescriptor extends ClassifierDescriptor, MemberDescriptor, ClassOrPackageFragmentDescriptor { +public interface ClassDescriptor extends ClassifierDescriptorWithTypeParameters, MemberDescriptor, ClassOrPackageFragmentDescriptor { @NotNull MemberScope getMemberScope(@NotNull List typeArguments); @@ -100,6 +100,7 @@ public interface ClassDescriptor extends ClassifierDescriptor, MemberDescriptor, * captured parameters from outer declaration. * @return list of type parameters actually declared type parameters in current class */ + @Override @ReadOnly @NotNull List getDeclaredTypeParameters(); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassifierDescriptorWithTypeParameters.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassifierDescriptorWithTypeParameters.java new file mode 100644 index 00000000000..9ad47fb57f4 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ClassifierDescriptorWithTypeParameters.java @@ -0,0 +1,28 @@ +/* + * 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.descriptors; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.ReadOnly; + +import java.util.List; + +public interface ClassifierDescriptorWithTypeParameters extends ClassifierDescriptor { + @ReadOnly + @NotNull + List getDeclaredTypeParameters(); +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/DeclarationDescriptorVisitor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/DeclarationDescriptorVisitor.java index 30abe3e37f4..499ab8ddb16 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/DeclarationDescriptorVisitor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/DeclarationDescriptorVisitor.java @@ -29,6 +29,8 @@ public interface DeclarationDescriptorVisitor { R visitClassDescriptor(ClassDescriptor descriptor, D data); + R visitTypeAliasDescriptor(TypeAliasDescriptor descriptor, D data); + R visitModuleDeclaration(ModuleDescriptor descriptor, D data); R visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, D data); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeAliasDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeAliasDescriptor.kt new file mode 100644 index 00000000000..e36b6d08eb0 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/TypeAliasDescriptor.kt @@ -0,0 +1,28 @@ +/* + * 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.descriptors + +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeSubstitutor + +interface TypeAliasDescriptor : ClassifierDescriptorWithTypeParameters, MemberDescriptor { + val underlyingType: KotlinType + + val underlyingClassDescriptor: ClassDescriptor + + override fun substitute(substitutor: TypeSubstitutor): TypeAliasDescriptor +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/DeclarationDescriptorVisitorEmptyBodies.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/DeclarationDescriptorVisitorEmptyBodies.java index 37e5d431f40..17b4706f635 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/DeclarationDescriptorVisitorEmptyBodies.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/DeclarationDescriptorVisitorEmptyBodies.java @@ -53,6 +53,11 @@ public class DeclarationDescriptorVisitorEmptyBodies implements Declaratio return visitDeclarationDescriptor(descriptor, data); } + @Override + public R visitTypeAliasDescriptor(TypeAliasDescriptor descriptor, D data) { + return visitDeclarationDescriptor(descriptor, data); + } + @Override public R visitModuleDeclaration(ModuleDescriptor descriptor, D data) { return visitDeclarationDescriptor(descriptor, data); diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index 6c65985b70d..3472a3e9d57 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -128,6 +128,19 @@ internal class DescriptorRendererImpl( } private fun renderNormalizedType(type: KotlinType): String { + val abbreviated = type.getCapability(AbbreviatedType::class.java)?.abbreviatedType + + if (abbreviated != null) { + // TODO nullability is lost for abbreviated type? + val abbreviatedRendered = renderNormalizedTypeAsIs(abbreviated) + val unabbreviatedRendered = renderNormalizedTypeAsIs(type) + return "$abbreviatedRendered [= $unabbreviatedRendered]" + } + + return renderNormalizedTypeAsIs(type) + } + + private fun renderNormalizedTypeAsIs(type: KotlinType): String { if (type is LazyType && debugMode) { return type.toString() } @@ -271,7 +284,7 @@ internal class DescriptorRendererImpl( override fun renderTypeConstructor(typeConstructor: TypeConstructor): String { val cd = typeConstructor.declarationDescriptor return when (cd) { - is TypeParameterDescriptor, is ClassDescriptor -> renderClassifierName(cd) + is TypeParameterDescriptor, is ClassDescriptor, is TypeAliasDescriptor -> renderClassifierName(cd) null -> typeConstructor.toString() else -> error("Unexpected classifier: " + cd.javaClass) } @@ -791,6 +804,15 @@ internal class DescriptorRendererImpl( } } + private fun renderTypeAlias(typeAlias: TypeAliasDescriptor, builder: StringBuilder) { + renderAnnotations(typeAlias, builder) + renderVisibility(typeAlias.visibility, builder) + builder.append(renderKeyword("typealias")).append(" ") + renderName(typeAlias, builder) + renderTypeParameters(typeAlias.declaredTypeParameters, builder, true) + builder.append(" = ").append(renderType(typeAlias.underlyingType)) + } + /* CLASSES */ private fun renderClass(klass: ClassDescriptor, builder: StringBuilder) { val isEnumEntry = klass.kind == ClassKind.ENUM_ENTRY @@ -961,6 +983,10 @@ internal class DescriptorRendererImpl( override fun visitClassDescriptor(descriptor: ClassDescriptor, builder: StringBuilder) { renderClass(descriptor, builder) } + + override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, builder: StringBuilder) { + renderTypeAlias(descriptor, builder) + } } private fun renderSpaceIfNeeded(builder: StringBuilder) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt index 749fe50f683..dc4e4ddef82 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeCapabilities.kt @@ -84,3 +84,13 @@ fun sameTypeConstructors(first: KotlinType, second: KotlinType): Boolean { return first.getCapability(typeRangeCapability)?.sameTypeConstructor(second) ?: false || second.getCapability(typeRangeCapability)?.sameTypeConstructor(first) ?: false } + +interface AbbreviatedType : TypeCapability { + val abbreviatedType : KotlinType +} + +fun KotlinType.hasAbbreviatedType(): Boolean = + getCapability(AbbreviatedType::class.java) != null + +fun KotlinType.getAbbreviatedType(): KotlinType? = + getCapability(AbbreviatedType::class.java)?.abbreviatedType diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java index 70ade7d5dc9..4360ec3c626 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.ClassDescriptor; +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; import org.jetbrains.kotlin.descriptors.annotations.Annotations; @@ -228,11 +229,11 @@ public class TypeUtils { } @NotNull - public static KotlinType makeUnsubstitutedType(ClassDescriptor classDescriptor, MemberScope unsubstitutedMemberScope) { - if (ErrorUtils.isError(classDescriptor)) { - return ErrorUtils.createErrorType("Unsubstituted type for " + classDescriptor); + public static KotlinType makeUnsubstitutedType(ClassifierDescriptor classifierDescriptor, MemberScope unsubstitutedMemberScope) { + if (ErrorUtils.isError(classifierDescriptor)) { + return ErrorUtils.createErrorType("Unsubstituted type for " + classifierDescriptor); } - TypeConstructor typeConstructor = classDescriptor.getTypeConstructor(); + TypeConstructor typeConstructor = classifierDescriptor.getTypeConstructor(); List arguments = getDefaultTypeProjections(typeConstructor.getParameters()); return KotlinTypeImpl.create( Annotations.Companion.getEMPTY(), diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index b2648f1f566..19168c6446b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -561,6 +561,8 @@ class ResolveElementCache( override fun getFunctions(): MutableMap = hashMapOf() + override fun getTypeAliases(): MutableMap = hashMapOf() + override fun getDeclaringScope(declaration: KtDeclaration): LexicalScope? = declaringScopes(declaration) override fun getScripts(): MutableMap = hashMapOf() diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index dcd9e2272d4..dc37432c329 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -105,7 +105,7 @@ class QuickFixRegistrar : QuickFixContributor { REDUNDANT_PROJECTION.registerFactory(RemoveModifierFix.createRemoveProjectionFactory(true)) INCOMPATIBLE_MODIFIERS.registerFactory(RemoveModifierFix.createRemoveModifierFactory(false)) - VARIANCE_ON_TYPE_PARAMETER_OF_FUNCTION_OR_PROPERTY.registerFactory(RemoveModifierFix.createRemoveVarianceFactory()) + VARIANCE_ON_TYPE_PARAMETER_NOT_ALLOWED.registerFactory(RemoveModifierFix.createRemoveVarianceFactory()) val removeOpenModifierFactory = RemoveModifierFix.createRemoveModifierFromListOwnerFactory(OPEN_KEYWORD) NON_FINAL_MEMBER_IN_FINAL_CLASS.registerFactory(AddModifierFix.createFactory(OPEN_KEYWORD, KtClass::class.java),