LTDA: Fix REPL and make it work with lazy resolve

This commit is contained in:
Nikolay Krasko
2014-11-18 19:06:58 +03:00
parent 994c8886bc
commit 602407cc9c
5 changed files with 166 additions and 38 deletions
@@ -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)
}
@@ -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("<repl>");
TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.createForLocalDeclarations(
new LockBasedStorageManager(),
new ExceptionTracker(), // dummy
Predicates.<PsiFile>alwaysTrue()
GlobalContextImpl context = ContextPackage.GlobalContext();
TopDownAnalysisParameters topDownAnalysisParameters = TopDownAnalysisParameters.createForLazy(
context.getStorageManager(),
context.getExceptionTracker(),
Predicates.<PsiFile>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<JetFile, JetScope>() {
@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);
}
}
}
}
@@ -388,6 +388,11 @@ public class LazyTopDownAnalyzer {
}
}
}
@NotNull
public KotlinCodeAnalyzer getCodeAnalyzer() {
return resolveSession;
}
}
@@ -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<JetFile, LazyImportScope> explicitImportScopes;
private final NotNullLazyValue<JetScope> defaultImportsScope;
private Function1<JetFile, JetScope> 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<JetScope> list = new ArrayList<JetScope>();
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<JetFile, JetScope> scopeProvider) {
this.additionalScopesProvider = scopeProvider;
}
@NotNull
@@ -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