From 602407cc9c5ebc738a8c7a5780411dbc6857a57e Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 18 Nov 2014 19:06:58 +0300 Subject: [PATCH] LTDA: Fix REPL and make it work with lazy resolve --- ...elegatePackageMemberDeclarationProvider.kt | 39 ++++++ .../jet/cli/jvm/repl/ReplInterpreter.java | 127 +++++++++++++----- .../jet/lang/resolve/LazyTopDownAnalyzer.java | 5 + .../jet/lang/resolve/lazy/ScopeProvider.java | 30 ++++- ...ombinedPackageMemberDeclarationProvider.kt | 3 +- 5 files changed, 166 insertions(+), 38 deletions(-) create mode 100644 compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt rename {idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/resolve => compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/declarations}/CombinedPackageMemberDeclarationProvider.kt (91%) diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt new file mode 100644 index 00000000000..ad07db03cdc --- /dev/null +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/DelegatePackageMemberDeclarationProvider.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2014 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.jet.cli.jvm.repl + +import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter +import org.jetbrains.jet.lang.psi.JetDeclaration + +open class DelegatePackageMemberDeclarationProvider(var delegate: PackageMemberDeclarationProvider) : PackageMemberDeclarationProvider { + // Can't use Kotlin delegate feature because of inability to change delegate object in runtime (KT-5870) + + override fun getAllDeclaredSubPackages() = delegate.getAllDeclaredSubPackages() + + override fun getPackageFiles() = delegate.getPackageFiles() + + override fun getDeclarations(kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean) = delegate.getDeclarations(kindFilter, nameFilter) + + override fun getFunctionDeclarations(name: Name) = delegate.getFunctionDeclarations(name) + + override fun getPropertyDeclarations(name: Name) = delegate.getPropertyDeclarations(name) + + override fun getClassOrObjectDeclarations(name: Name) = delegate.getClassOrObjectDeclarations(name) +} \ No newline at end of file diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java index 72dc9a17c70..27150e39a47 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/repl/ReplInterpreter.java @@ -27,7 +27,9 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.psi.impl.PsiFileFactoryImpl; +import com.intellij.psi.search.ProjectScope; import com.intellij.testFramework.LightVirtualFile; +import kotlin.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.OutputFile; @@ -41,26 +43,25 @@ import org.jetbrains.jet.codegen.CompilationErrorHandler; import org.jetbrains.jet.codegen.KotlinCodegenFacade; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.config.CompilerConfiguration; +import org.jetbrains.jet.context.ContextPackage; +import org.jetbrains.jet.context.GlobalContextImpl; import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm; import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.descriptors.impl.CompositePackageFragmentProvider; import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl; -import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilderDummy; import org.jetbrains.jet.lang.parsing.JetParserDefinition; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetScript; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.TopDownAnalyzerFacadeForJVM; +import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo; +import org.jetbrains.jet.lang.resolve.lazy.declarations.*; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.WritableScope; -import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.plugin.JetLanguage; -import org.jetbrains.jet.storage.ExceptionTracker; -import org.jetbrains.jet.storage.LockBasedStorageManager; import org.jetbrains.jet.utils.UtilsPackage; import org.jetbrains.org.objectweb.asm.Type; @@ -92,8 +93,10 @@ public class ReplInterpreter { private final PsiFileFactoryImpl psiFileFactory; private final BindingTraceContext trace; private final ModuleDescriptorImpl module; + private final TopDownAnalysisContext topDownAnalysisContext; - private final TopDownAnalyzer topDownAnalyzer; + private final LazyTopDownAnalyzer topDownAnalyzer; + private final ScriptMutableDeclarationProviderFactory scriptDeclarationFactory; public ReplInterpreter(@NotNull Disposable disposable, @NotNull CompilerConfiguration configuration) { JetCoreEnvironment environment = JetCoreEnvironment.createForProduction(disposable, configuration); @@ -101,20 +104,41 @@ public class ReplInterpreter { this.psiFileFactory = (PsiFileFactoryImpl) PsiFileFactory.getInstance(project); this.trace = new BindingTraceContext(); this.module = TopDownAnalyzerFacadeForJVM.createJavaModule(""); - TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.createForLocalDeclarations( - new LockBasedStorageManager(), - new ExceptionTracker(), // dummy - Predicates.alwaysTrue() + + GlobalContextImpl context = ContextPackage.GlobalContext(); + + TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.createForLazy( + context.getStorageManager(), + context.getExceptionTracker(), + Predicates.alwaysTrue(), + false, + true ); - // FIXME: Make it work for lazy resolve - InjectorForTopDownAnalyzerForJvm injector = null; + scriptDeclarationFactory = new ScriptMutableDeclarationProviderFactory(); + + InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm( + project, + context, + trace, + module, + ProjectScope.getAllScope(project), + scriptDeclarationFactory + ); + this.topDownAnalysisContext = new TopDownAnalysisContext(topDownAnalysisParameters); - this.topDownAnalyzer = null; + this.topDownAnalyzer = injector.getLazyTopDownAnalyzer(); + + this.topDownAnalyzer.getCodeAnalyzer().getScopeProvider().setAdditionalFileScopesProvider(new Function1() { + @Override + public JetScope invoke(JetFile file) { + return lastLineScope; + } + }); module.initialize(new CompositePackageFragmentProvider( Arrays.asList( - topDownAnalyzer.getPackageFragmentProvider(), + injector.getResolveSession().getPackageFragmentProvider(), injector.getJavaDescriptorResolver().getPackageFragmentProvider() ) )); @@ -322,33 +346,23 @@ public class ReplInterpreter { @Nullable private ScriptDescriptor doAnalyze(@NotNull JetFile psiFile, @NotNull MessageCollector messageCollector) { - WritableScope scope = new WritableScopeImpl( - JetScope.Empty.INSTANCE$, module, - new TraceBasedRedeclarationHandler(trace), "Root scope in analyzePackage" - ); + scriptDeclarationFactory.setDelegateFactory( + new FileBasedDeclarationProviderFactory(topDownAnalysisContext.getStorageManager(), Collections.singletonList(psiFile))); - scope.changeLockLevel(WritableScope.LockLevel.BOTH); + TopDownAnalysisContext context = topDownAnalyzer.analyzeDeclarations( + topDownAnalysisContext.getTopDownAnalysisParameters(), + Collections.singletonList(psiFile)); - // Import a scope that contains all top-level packages that come from dependencies - // This makes the packages visible at all, does not import themselves - scope.importScope(module.getPackage(FqName.ROOT).getMemberScope()); - - if (lastLineScope != null) { - scope.importScope(lastLineScope); + if (trace.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile) == null) { + trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, psiFile, topDownAnalyzer.getCodeAnalyzer().getPackageFragment(FqName.ROOT)); } - scope.changeLockLevel(WritableScope.LockLevel.READING); - - // dummy builder is used because "root" is module descriptor, - // packages added to module explicitly in - topDownAnalyzer.doProcess(topDownAnalysisContext, scope, new PackageLikeBuilderDummy(), Collections.singletonList(psiFile)); - boolean hasErrors = AnalyzerWithCompilerReport.reportDiagnostics(trace.getBindingContext().getDiagnostics(), messageCollector); if (hasErrors) { return null; } - ScriptDescriptor scriptDescriptor = topDownAnalysisContext.getScripts().get(psiFile.getScript()); + ScriptDescriptor scriptDescriptor = context.getScripts().get(psiFile.getScript()); lastLineScope = trace.get(BindingContext.SCRIPT_SCOPE, scriptDescriptor); if (lastLineScope == null) { throw new IllegalStateException("last line scope is not initialized"); @@ -398,4 +412,53 @@ public class ReplInterpreter { ); } + private static class ScriptMutableDeclarationProviderFactory implements DeclarationProviderFactory { + private DeclarationProviderFactory delegateFactory; + private AdaptablePackageMemberDeclarationProvider rootPackageProvider; + + public void setDelegateFactory(DeclarationProviderFactory delegateFactory) { + this.delegateFactory = delegateFactory; + + PackageMemberDeclarationProvider provider = delegateFactory.getPackageMemberDeclarationProvider(FqName.ROOT); + if (rootPackageProvider == null) { + assert provider != null; + rootPackageProvider = new AdaptablePackageMemberDeclarationProvider(provider); + } + else { + rootPackageProvider.addDelegateProvider(provider); + } + } + + @NotNull + @Override + public ClassMemberDeclarationProvider getClassMemberDeclarationProvider(@NotNull JetClassLikeInfo classLikeInfo) { + return delegateFactory.getClassMemberDeclarationProvider(classLikeInfo); + } + + @Nullable + @Override + public PackageMemberDeclarationProvider getPackageMemberDeclarationProvider(@NotNull FqName packageFqName) { + if (packageFqName.isRoot()) { + return rootPackageProvider; + } + + return this.delegateFactory.getPackageMemberDeclarationProvider(packageFqName); + } + + public static class AdaptablePackageMemberDeclarationProvider extends DelegatePackageMemberDeclarationProvider { + @NotNull + private PackageMemberDeclarationProvider delegateProvider; + + public AdaptablePackageMemberDeclarationProvider(@NotNull PackageMemberDeclarationProvider delegateProvider) { + super(delegateProvider); + this.delegateProvider = delegateProvider; + } + + public void addDelegateProvider(PackageMemberDeclarationProvider provider) { + delegateProvider = new CombinedPackageMemberDeclarationProvider(Lists.newArrayList(provider, delegateProvider)); + + setDelegate(delegateProvider); + } + } + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java index d8f8b654d40..403c308a8d6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/LazyTopDownAnalyzer.java @@ -388,6 +388,11 @@ public class LazyTopDownAnalyzer { } } } + + @NotNull + public KotlinCodeAnalyzer getCodeAnalyzer() { + return resolveSession; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ScopeProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ScopeProvider.java index 393a26aaf4c..3e2ea2871e6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ScopeProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ScopeProvider.java @@ -30,9 +30,11 @@ import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.storage.LockBasedStorageManager; import org.jetbrains.jet.storage.MemoizedFunctionToNotNull; import org.jetbrains.jet.storage.NotNullLazyValue; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -42,6 +44,7 @@ public class ScopeProvider { private final MemoizedFunctionToNotNull explicitImportScopes; private final NotNullLazyValue defaultImportsScope; + private Function1 additionalScopesProvider; public ScopeProvider(@NotNull ResolveSession resolveSession) { this.resolveSession = resolveSession; @@ -74,10 +77,29 @@ public class ScopeProvider { public JetScope getFileScope(@NotNull JetFile file) { return new ChainedScope(resolveSession.getPackageFragment(file.getPackageFqName()), "File scope: " + file.getName(), - getFilePackageDescriptor(file).getMemberScope(), - JetModuleUtil.getSubpackagesOfRootScope(resolveSession.getModuleDescriptor()), - explicitImportScopes.invoke(file), - defaultImportsScope.invoke()); + collectFileScopes(file)); + } + + public JetScope[] collectFileScopes(@NotNull JetFile file) { + List list = new ArrayList(); + list.add(getFilePackageDescriptor(file).getMemberScope()); + list.add(JetModuleUtil.getSubpackagesOfRootScope(resolveSession.getModuleDescriptor())); + list.add(explicitImportScopes.invoke(file)); + + if (additionalScopesProvider != null) { + JetScope additionalScope = additionalScopesProvider.invoke(file); + if (additionalScope != null) { + list.add(additionalScope); + } + } + + list.add(defaultImportsScope.invoke()); + + return list.toArray(new JetScope[list.size()]); + } + + public void setAdditionalFileScopesProvider(@NotNull Function1 scopeProvider) { + this.additionalScopesProvider = scopeProvider; } @NotNull diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/resolve/CombinedPackageMemberDeclarationProvider.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt similarity index 91% rename from idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/resolve/CombinedPackageMemberDeclarationProvider.kt rename to compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt index a1ac1469433..bbdb77235bd 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/resolve/CombinedPackageMemberDeclarationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/declarations/CombinedPackageMemberDeclarationProvider.kt @@ -14,9 +14,8 @@ * limitations under the License. */ -package org.jetbrains.jet.plugin.stubindex.resolve +package org.jetbrains.jet.lang.resolve.lazy.declarations -import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider import org.jetbrains.jet.lang.resolve.name.Name import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter