File class lowering

This commit is contained in:
Dmitry Petrov
2016-09-14 10:58:45 +03:00
committed by Dmitry Petrov
parent a25e781ee9
commit 5386d27284
17 changed files with 380 additions and 22 deletions
+2
View File
@@ -11,5 +11,7 @@
<orderEntry type="module" module-name="ir.tree" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="backend" />
<orderEntry type="module" module-name="ir.psi2ir" />
<orderEntry type="module" module-name="frontend.java" />
</component>
</module>
@@ -0,0 +1,39 @@
/*
* 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.backend.jvm
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.util.render
import java.lang.AssertionError
class JvmBackend(context: JvmBackendContext) {
private val lower = JvmLower(context)
private val codegen = JvmCodegen(context)
fun generateFile(irFile: IrFile) {
val loweredFile = lower.lower(irFile)
for (loweredClass in loweredFile.declarations) {
if (loweredClass !is IrClass) {
throw AssertionError("File-level declaration should be IrClass after JvmLower, got: " + loweredClass.render())
}
codegen.generateClass(loweredClass)
}
}
}
@@ -0,0 +1,25 @@
/*
* 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.backend.jvm
import org.jetbrains.kotlin.backend.jvm.lower.JvmFileClassProvider
import org.jetbrains.kotlin.codegen.state.GenerationState
class JvmBackendContext(
val state: GenerationState,
val jvmFileClassProvider: JvmFileClassProvider
)
@@ -16,10 +16,13 @@
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.jvm.lower.JvmFileClassProvider
import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
object JvmBackendFacade {
fun compileCorrectFiles(state: GenerationState, errorHandler: CompilationErrorHandler) {
@@ -30,6 +33,33 @@ object JvmBackendFacade {
}
fun doGenerateFiles(files: Collection<KtFile>, state: GenerationState, errorHandler: CompilationErrorHandler) {
// TODO
// TODO multifile classes support
val psi2ir = Psi2IrTranslator()
val psi2irContext = psi2ir.createGeneratorContext(state.module, state.bindingContext)
val jvmBackendContext = createJvmBackendContext(psi2ir, state)
val jvmBackend = JvmBackend(jvmBackendContext)
val irModuleFragment = psi2ir.generateModuleFragment(psi2irContext, files)
for (ktFile in irModuleFragment.files) {
try {
jvmBackend.generateFile(ktFile)
state.afterIndependentPart()
}
catch (e: Throwable) {
errorHandler.reportException(e, null) // TODO ktFile.virtualFile.url
}
}
}
private fun createJvmBackendContext(psi2ir: Psi2IrTranslator, state: GenerationState): JvmBackendContext {
val jvmFileClassProvider = JvmFileClassProvider()
psi2ir.add(jvmFileClassProvider)
val jvmBackendContext = JvmBackendContext(state, jvmFileClassProvider)
return jvmBackendContext
}
}
@@ -0,0 +1,25 @@
/*
* 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.backend.jvm
import org.jetbrains.kotlin.ir.declarations.IrClass
class JvmCodegen(val context: JvmBackendContext) {
fun generateClass(irClass: IrClass) {
// TODO
}
}
@@ -0,0 +1,30 @@
/*
* 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.backend.jvm
import org.jetbrains.kotlin.backend.jvm.lower.FileClassLowering
import org.jetbrains.kotlin.ir.declarations.IrFile
class JvmLower(val context: JvmBackendContext) {
fun lower(irFile: IrFile): IrFile {
var newIrFile = irFile
newIrFile = FileClassLowering(context).lower(newIrFile)
return newIrFile
}
}
@@ -0,0 +1,70 @@
/*
* 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.backend.jvm.lower
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.*
interface FileClassDescriptor : ClassDescriptor
class FileClassDescriptorImpl(
private val nameImpl: Name,
private val containingDeclarationImpl: PackageFragmentDescriptor,
private val sourceElement: SourceElement
) : FileClassDescriptor {
override fun getCompanionObjectDescriptor(): ClassDescriptor? = null
override fun getConstructors(): Collection<ConstructorDescriptor> = emptyList()
override fun getContainingDeclaration(): DeclarationDescriptor = containingDeclarationImpl
override fun getDeclaredTypeParameters(): List<TypeParameterDescriptor> = emptyList()
override fun getDefaultType(): SimpleType = ErrorUtils.createErrorType("File class type for $nameImpl")
override fun getKind(): ClassKind = ClassKind.CLASS
override fun getMemberScope(typeArguments: MutableList<out TypeProjection>): MemberScope = error("File class has no member scope")
override fun getMemberScope(typeSubstitution: TypeSubstitution): MemberScope = error("File class has no member scope")
override fun getModality(): Modality = Modality.FINAL
override fun getOriginal(): ClassDescriptor = this
override fun getName(): Name = nameImpl
override fun getStaticScope(): MemberScope = error("File class has no static scope")
override fun getThisAsReceiverParameter(): ReceiverParameterDescriptor = error("File class has no instances")
override fun getUnsubstitutedInnerClassesScope(): MemberScope = error("File class has no inner classes scope")
override fun getUnsubstitutedMemberScope(): MemberScope = error("File class has no member scope")
override fun getUnsubstitutedPrimaryConstructor(): ConstructorDescriptor? = null
override fun getVisibility(): Visibility = Visibilities.PUBLIC
override fun isCompanionObject(): Boolean = false
override fun isData(): Boolean = false
override fun substitute(substitutor: TypeSubstitutor): ClassDescriptor = error("File class can't be substituted")
override fun getSource(): SourceElement = sourceElement
override fun getTypeConstructor(): TypeConstructor = error("File class can't be used in types")
override fun isInner(): Boolean = false
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R {
return visitor.visitClassDescriptor(this, data)
}
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>) {
visitor.visitClassDescriptor(this, null)
}
override val annotations: Annotations
get() = TODO("not implemented")
override fun toString(): String =
"IrFileClassDescriptor($fqNameUnsafe)"
}
@@ -0,0 +1,51 @@
/*
* 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.backend.jvm.lower
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import java.util.*
class FileClassLowering(val context: JvmBackendContext) {
fun lower(irFile: IrFile): IrFile {
val classes = ArrayList<IrClass>()
val fileClassMembers = ArrayList<IrDeclaration>()
irFile.declarations.forEach {
if (it is IrClass)
classes.add(it)
else
fileClassMembers.add(it)
}
if (fileClassMembers.isEmpty()) return irFile
val fileClassDescriptor = context.jvmFileClassProvider.createFileClassDescriptor(irFile.fileEntry, irFile.packageFragmentDescriptor)
val irFileClass = IrClassImpl(0, irFile.fileEntry.maxOffset, IrDeclarationOrigin.DEFINED, fileClassDescriptor, fileClassMembers)
classes.add(irFileClass)
val newIrFile = irFile.toBuilder().apply { declarations.clear(); declarations.addAll(classes) }.build()
return newIrFile
}
}
@@ -0,0 +1,61 @@
/*
* 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.backend.jvm.lower
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import java.lang.AssertionError
import java.util.*
class JvmFileClassProvider : Psi2IrTranslator.PostprocessingStep {
override fun postprocess(context: GeneratorContext, irElement: IrElement) {
when (irElement) {
is IrModuleFragment ->
irElement.files.forEach { postprocess(context, it) }
is IrFile ->
recordFileClassInfo(context, irElement)
}
}
private val fileClassInfoByFileEntry = HashMap<SourceManager.FileEntry, JvmFileClassInfo>()
private fun recordFileClassInfo(context: GeneratorContext, irFile: IrFile) {
val jvmFileClassInfo = context.sourceManager.getFileClassInfo(irFile.fileEntry)
fileClassInfoByFileEntry[irFile.fileEntry] = jvmFileClassInfo
}
private fun PsiSourceManager.getKtFile(fileEntry: SourceManager.FileEntry) =
getPsiFile(fileEntry as PsiSourceManager.PsiFileEntry) as KtFile
private fun PsiSourceManager.getFileClassInfo(fileEntry: SourceManager.FileEntry): JvmFileClassInfo =
JvmFileClassUtil.getFileClassInfoNoResolve(getKtFile(fileEntry))
fun createFileClassDescriptor(fileEntry: SourceManager.FileEntry, packageFragment: PackageFragmentDescriptor): FileClassDescriptor {
val fileClassInfo = fileClassInfoByFileEntry[fileEntry] ?: throw AssertionError("No file class info for ${fileEntry.name})")
return FileClassDescriptorImpl(fileClassInfo.fileClassFqName.shortName(), packageFragment, SourceElement.NO_SOURCE)
}
}
@@ -17,5 +17,5 @@
package org.jetbrains.kotlin.psi2ir
class Psi2IrConfiguration(
val ignoreErrors: Boolean
val ignoreErrors: Boolean = false
)
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -25,23 +24,36 @@ import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator
import org.jetbrains.kotlin.psi2ir.transformations.insertImplicitCasts
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.utils.SmartList
class Psi2IrTranslator(val configuration: Psi2IrConfiguration) {
fun generateModule(moduleDescriptor: ModuleDescriptor, ktFiles: List<KtFile>, bindingContext: BindingContext): IrModuleFragment {
val context = GeneratorContext(configuration, moduleDescriptor, bindingContext)
class Psi2IrTranslator(val configuration: Psi2IrConfiguration = Psi2IrConfiguration()) {
interface PostprocessingStep {
fun postprocess(context: GeneratorContext, irElement: IrElement)
}
private val postprocessingSteps = SmartList<PostprocessingStep>()
fun add(step: PostprocessingStep) {
postprocessingSteps.add(step)
}
fun generateModule(moduleDescriptor: ModuleDescriptor, ktFiles: Collection<KtFile>, bindingContext: BindingContext): IrModuleFragment {
val context = createGeneratorContext(moduleDescriptor, bindingContext)
return generateModuleFragment(context, ktFiles)
}
fun createGeneratorContext(moduleDescriptor: ModuleDescriptor, bindingContext: BindingContext) =
GeneratorContext(configuration, moduleDescriptor, bindingContext)
fun generateModuleFragment(context: GeneratorContext, ktFiles: Collection<KtFile>): IrModuleFragment {
val irModule = ModuleGenerator(context).generateModuleFragment(ktFiles)
postprocess(irModule.descriptor.builtIns, irModule)
postprocess(context, irModule)
return irModule
}
fun generateSingleFileFragment(moduleDescriptor: ModuleDescriptor, ktFile: KtFile, bindingContext: BindingContext): IrModuleFragment {
val context = GeneratorContext(configuration, moduleDescriptor, bindingContext)
val irFileFragment = ModuleGenerator(context).generateSingleFileFragment(ktFile)
postprocess(moduleDescriptor.builtIns, irFileFragment)
return irFileFragment
}
private fun postprocess(context: GeneratorContext, irElement: IrElement) {
insertImplicitCasts(context.builtIns, irElement)
private fun postprocess(builtIns: KotlinBuiltIns, irElement: IrElement) {
insertImplicitCasts(builtIns, irElement)
postprocessingSteps.forEach { it.postprocess(context, irElement) }
}
}
@@ -69,11 +69,13 @@ class PsiSourceManager : SourceManager {
private val fileEntriesByPsiFile = HashMap<PsiFile, PsiFileEntry>()
private val fileEntriesByIrFile = HashMap<IrFile, PsiFileEntry>()
private val psiFileByFileEntry = HashMap<PsiFileEntry, PsiFile>()
fun createFileEntry(psiFile: PsiFile): PsiFileEntry {
if (psiFile in fileEntriesByPsiFile) error("PsiFileEntry is already created for $psiFile")
val newEntry = PsiFileEntry(psiFile)
fileEntriesByPsiFile[psiFile] = newEntry
psiFileByFileEntry[newEntry] = psiFile
return newEntry
}
@@ -87,6 +89,9 @@ class PsiSourceManager : SourceManager {
fun getFileEntry(psiFile: PsiFile): PsiFileEntry? =
fileEntriesByPsiFile[psiFile]
fun getPsiFile(fileEntry: PsiFileEntry) =
psiFileByFileEntry[fileEntry]
override fun getFileEntry(irFile: IrFile): SourceManager.FileEntry =
fileEntriesByIrFile[irFile]!!
}
@@ -30,7 +30,6 @@ class GeneratorContext(
val bindingContext: BindingContext
) {
val sourceManager = PsiSourceManager()
val syntheticDescriptorsFactory = SyntheticDescriptorsFactory()
val reflectionTypes = ReflectionTypes(moduleDescriptor)
val builtIns: KotlinBuiltIns get() = moduleDescriptor.builtIns
@@ -18,8 +18,10 @@ package org.jetbrains.kotlin.ir.declarations
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.checkAnnotationName
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.name.FqName
interface IrFile : IrElement, IrDeclarationContainer {
val fileEntry: SourceManager.FileEntry
@@ -37,4 +39,7 @@ interface IrFile : IrElement, IrDeclarationContainer {
}
}
val IrFile.name: String get() = fileEntry.name
val IrFile.name: String get() = fileEntry.name
fun IrFile.findAnnotationsByFqName(fqName: FqName) =
fileAnnotations.filter { checkAnnotationName(it, fqName) }
@@ -73,10 +73,10 @@ class IrClassImpl(
}
class IrClassBuilderImpl(
override val startOffset: Int,
override val endOffset: Int,
override var startOffset: Int,
override var endOffset: Int,
override var origin: IrDeclarationOrigin,
override val descriptor: ClassDescriptor,
override var descriptor: ClassDescriptor,
override val declarations: MutableList<IrDeclaration>
) : IrClass.Builder {
constructor(irClass: IrClass) : this(irClass.startOffset, irClass.endOffset, irClass.origin, irClass.descriptor,
@@ -75,7 +75,7 @@ interface Annotations : Iterable<AnnotationDescriptor> {
}
}
private fun checkAnnotationName(annotation: AnnotationDescriptor, fqName: FqName): Boolean {
fun checkAnnotationName(annotation: AnnotationDescriptor, fqName: FqName): Boolean {
val descriptor = annotation.type.constructor.declarationDescriptor
return descriptor is ClassDescriptor && fqName.toUnsafe() == DescriptorUtils.getFqName(descriptor)
}
@@ -520,7 +520,11 @@ public class DescriptorUtils {
@Nullable
public static String getJvmName(@NotNull Annotated annotated) {
AnnotationDescriptor jvmNameAnnotation = getAnnotationByFqName(annotated.getAnnotations(), JVM_NAME);
return getJvmName(getJvmNameAnnotation(annotated));
}
@Nullable
public static String getJvmName(@Nullable AnnotationDescriptor jvmNameAnnotation) {
if (jvmNameAnnotation == null) return null;
Map<ValueParameterDescriptor, ConstantValue<?>> arguments = jvmNameAnnotation.getAllValueArguments();