mirror of
https://github.com/enso-org/enso.git
synced 2025-01-03 15:06:34 +03:00
Refactor: split IrToTruffle::processModule
into smaller sub-methods (#10587)
- This PR only re-arranges code, splitting the **huge** `processModule` function into a few smaller ones. - I decided to do it, because when I was working with `processModule` on #9812 I was constantly getting lost in this huge method (this **one** method had 570 lines!) - there is too much happening at once there. Now it's been split into smaller methods, each dealing with one thing.
This commit is contained in:
parent
473a51cee7
commit
4e310d723d
@ -41,10 +41,12 @@ import org.enso.compiler.core.ir.expression.{
|
||||
Operator,
|
||||
Section
|
||||
}
|
||||
import org.enso.compiler.core.ir.module.scope.definition.Method
|
||||
import org.enso.compiler.data.BindingsMap.{ResolvedConstructor, ResolvedModule}
|
||||
import org.enso.compiler.data.{BindingsMap, CompilerConfig}
|
||||
import org.enso.compiler.exception.BadPatternMatch
|
||||
import org.enso.compiler.pass.analyse.alias.Graph.{Scope => AliasScope}
|
||||
import org.enso.compiler.pass.analyse.alias.Info.Scope
|
||||
import org.enso.compiler.pass.analyse.{
|
||||
AliasAnalysis,
|
||||
BindingAnalysis,
|
||||
@ -193,6 +195,18 @@ class IrToTruffle(
|
||||
"No binding analysis at the point of codegen."
|
||||
)
|
||||
|
||||
registerModuleExports(bindingsMap)
|
||||
registerModuleImports(bindingsMap)
|
||||
registerPolyglotImports(module)
|
||||
|
||||
registerTypeDefinitions(module)
|
||||
registerMethodDefinitions(module)
|
||||
registerConversions(module)
|
||||
|
||||
scopeBuilder.build()
|
||||
}
|
||||
|
||||
private def registerModuleExports(bindingsMap: BindingsMap): Unit =
|
||||
bindingsMap.getDirectlyExportedModules.foreach { exportedMod =>
|
||||
val exportedRuntimeMod = exportedMod.module.module.unsafeAsModule()
|
||||
scopeBuilder.addExport(
|
||||
@ -200,11 +214,7 @@ class IrToTruffle(
|
||||
)
|
||||
}
|
||||
|
||||
val importDefs = module.imports
|
||||
val methodDefs = module.bindings.collect {
|
||||
case method: definition.Method.Explicit => method
|
||||
}
|
||||
|
||||
private def registerModuleImports(bindingsMap: BindingsMap): Unit =
|
||||
bindingsMap.resolvedImports.foreach { imp =>
|
||||
imp.targets.foreach {
|
||||
case _: BindingsMap.ResolvedType =>
|
||||
@ -222,8 +232,8 @@ class IrToTruffle(
|
||||
}
|
||||
}
|
||||
|
||||
// Register the imports in scope
|
||||
importDefs.foreach {
|
||||
private def registerPolyglotImports(module: Module): Unit =
|
||||
module.imports.foreach {
|
||||
case poly @ imports.Polyglot(i: imports.Polyglot.Java, _, _, _, _) =>
|
||||
var hostSymbol = context.lookupJavaClass(i.getJavaName)
|
||||
if (hostSymbol == null) {
|
||||
@ -240,6 +250,7 @@ class IrToTruffle(
|
||||
case _: Error =>
|
||||
}
|
||||
|
||||
private def registerTypeDefinitions(module: Module): Unit = {
|
||||
val typeDefs = module.bindings.collect { case tp: Definition.Type => tp }
|
||||
typeDefs.foreach { tpDef =>
|
||||
// Register the atoms and their constructors in scope
|
||||
@ -250,6 +261,17 @@ class IrToTruffle(
|
||||
atomConstructors
|
||||
.zip(atomDefs)
|
||||
.foreach { case (atomCons, atomDefn) =>
|
||||
registerAtomConstructor(tpDef, atomCons, atomDefn)
|
||||
}
|
||||
asType.generateGetters(language)
|
||||
}
|
||||
}
|
||||
|
||||
private def registerAtomConstructor(
|
||||
tpDef: Definition.Type,
|
||||
atomCons: AtomConstructor,
|
||||
atomDefn: Definition.Data
|
||||
): Unit = {
|
||||
val scopeInfo = atomDefn
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
@ -347,10 +369,12 @@ class IrToTruffle(
|
||||
)
|
||||
}
|
||||
}
|
||||
asType.generateGetters(language)
|
||||
|
||||
private def registerMethodDefinitions(module: Module): Unit = {
|
||||
val methodDefs = module.bindings.collect {
|
||||
case method: definition.Method.Explicit => method
|
||||
}
|
||||
|
||||
// Register the method definitions in scope
|
||||
methodDefs.foreach(methodDef => {
|
||||
val scopeInfo = methodDef
|
||||
.unsafeGetMetadata(
|
||||
@ -380,45 +404,7 @@ class IrToTruffle(
|
||||
.flatMap(sig => getContext(sig.signature))
|
||||
|
||||
val declaredConsOpt =
|
||||
methodDef.methodReference.typePointer match {
|
||||
case None =>
|
||||
Some(scopeAssociatedType)
|
||||
case Some(tpePointer) =>
|
||||
tpePointer
|
||||
.getMetadata(MethodDefinitions)
|
||||
.map { res =>
|
||||
res.target match {
|
||||
case binding @ BindingsMap.ResolvedType(_, _) =>
|
||||
asType(binding)
|
||||
case BindingsMap.ResolvedModule(module) =>
|
||||
asAssociatedType(module.unsafeAsModule())
|
||||
case BindingsMap.ResolvedConstructor(_, _) =>
|
||||
throw new CompilerError(
|
||||
"Impossible, should be caught by MethodDefinitions pass"
|
||||
)
|
||||
case BindingsMap.ResolvedPolyglotSymbol(_, _) =>
|
||||
throw new CompilerError(
|
||||
"Impossible polyglot symbol, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
case BindingsMap.ResolvedPolyglotField(_, _) =>
|
||||
throw new CompilerError(
|
||||
"Impossible polyglot field, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
case _: BindingsMap.ResolvedModuleMethod =>
|
||||
throw new CompilerError(
|
||||
"Impossible module method here, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
case _: BindingsMap.ResolvedExtensionMethod =>
|
||||
throw new CompilerError(
|
||||
"Impossible static method here, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
case _: BindingsMap.ResolvedConversionMethod =>
|
||||
throw new CompilerError(
|
||||
"Impossible conversion method here, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
getTypeAssociatedWithMethodDefinition(methodDef)
|
||||
|
||||
val consOpt = declaredConsOpt.map { c =>
|
||||
if (methodDef.isStatic) {
|
||||
@ -441,8 +427,199 @@ class IrToTruffle(
|
||||
cons,
|
||||
methodDef.methodName.name,
|
||||
() => {
|
||||
buildFunction(
|
||||
methodDef,
|
||||
effectContext,
|
||||
cons,
|
||||
fullMethodDefName,
|
||||
expressionProcessor
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private def buildFunction(
|
||||
methodDef: Method.Explicit,
|
||||
effectContext: Option[String],
|
||||
cons: Type,
|
||||
fullMethodDefName: String,
|
||||
expressionProcessor: ExpressionProcessor
|
||||
): RuntimeFunction = {
|
||||
val function = methodDef.body match {
|
||||
case fn: Function if isBuiltinMethod(fn.body) =>
|
||||
buildBuiltinFunction(
|
||||
fn,
|
||||
expressionProcessor,
|
||||
methodDef,
|
||||
effectContext,
|
||||
cons,
|
||||
fullMethodDefName
|
||||
)
|
||||
case fn: Function =>
|
||||
Right(
|
||||
Some(
|
||||
buildRegularFunction(
|
||||
methodDef,
|
||||
effectContext,
|
||||
cons,
|
||||
fullMethodDefName,
|
||||
expressionProcessor,
|
||||
fn
|
||||
)
|
||||
)
|
||||
)
|
||||
case _ =>
|
||||
Left(
|
||||
new CompilerError(
|
||||
"Method bodies must be functions at the point of codegen."
|
||||
)
|
||||
)
|
||||
}
|
||||
function match {
|
||||
case Left(failure) =>
|
||||
throw failure
|
||||
case Right(Some(fun)) =>
|
||||
fun
|
||||
case x =>
|
||||
throw new IllegalStateException("Wrong state: " + x)
|
||||
}
|
||||
}
|
||||
|
||||
private def buildRegularFunction(
|
||||
methodDef: Method.Explicit,
|
||||
effectContext: Option[String],
|
||||
cons: Type,
|
||||
fullMethodDefName: String,
|
||||
expressionProcessor: ExpressionProcessor,
|
||||
fn: Function
|
||||
): RuntimeFunction = {
|
||||
val bodyBuilder =
|
||||
new expressionProcessor.BuildFunctionBody(
|
||||
fullMethodDefName,
|
||||
fn.arguments,
|
||||
fn.body,
|
||||
null,
|
||||
effectContext,
|
||||
true
|
||||
)
|
||||
|
||||
val operators = ".!$%&*+-/<>?^~\\="
|
||||
|
||||
def isOperator(n: Name): Boolean = {
|
||||
n.name
|
||||
.chars()
|
||||
.allMatch(operators.indexOf(_) >= 0)
|
||||
}
|
||||
|
||||
val arguments = bodyBuilder.args()
|
||||
val rootNode =
|
||||
if (arguments.size == 2 && isOperator(methodDef.methodName)) {
|
||||
MethodRootNode.buildOperator(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
scopeBuilder.asModuleScope(),
|
||||
() => bodyBuilder.argsExpr._1(0),
|
||||
() => bodyBuilder.argsExpr._1(1),
|
||||
() => bodyBuilder.argsExpr._2,
|
||||
makeSection(scopeBuilder.getModule, methodDef.location),
|
||||
cons,
|
||||
methodDef.methodName.name
|
||||
)
|
||||
} else {
|
||||
MethodRootNode.build(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
scopeBuilder.asModuleScope(),
|
||||
() => bodyBuilder.bodyNode(),
|
||||
makeSection(scopeBuilder.getModule, methodDef.location),
|
||||
cons,
|
||||
methodDef.methodName.name
|
||||
)
|
||||
}
|
||||
val callTarget = rootNode.getCallTarget
|
||||
// build annotations
|
||||
val annotations =
|
||||
methodDef.getMetadata(GenericAnnotations).toVector.flatMap { meta =>
|
||||
meta.annotations
|
||||
.collect { case annotation: Name.GenericAnnotation =>
|
||||
val scopeElements = Seq(
|
||||
cons.getName,
|
||||
methodDef.methodName.name,
|
||||
annotation.name
|
||||
)
|
||||
val scopeName =
|
||||
scopeElements.mkString(Constants.SCOPE_SEPARATOR)
|
||||
val scopeInfo = annotation
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
s"Missing scope information for annotation " +
|
||||
s"${annotation.name} of method " +
|
||||
scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)
|
||||
)
|
||||
.unsafeAs[Scope.Root]
|
||||
val dataflowInfo = annotation.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Missing dataflow information for annotation " +
|
||||
s"${annotation.name} of method " +
|
||||
scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)
|
||||
)
|
||||
val expressionProcessor = new ExpressionProcessor(
|
||||
scopeName,
|
||||
scopeInfo.graph,
|
||||
scopeInfo.graph.rootScope,
|
||||
dataflowInfo,
|
||||
methodDef.methodName.name
|
||||
)
|
||||
val expressionNode =
|
||||
expressionProcessor.run(annotation.expression, true)
|
||||
val closureName =
|
||||
s"<default::${expressionProcessor.scopeName}>"
|
||||
val closureRootNode = ClosureRootNode.build(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
scopeBuilder.asModuleScope(),
|
||||
expressionNode,
|
||||
makeSection(
|
||||
scopeBuilder.getModule,
|
||||
annotation.location
|
||||
),
|
||||
closureName,
|
||||
true,
|
||||
false
|
||||
)
|
||||
new RuntimeAnnotation(
|
||||
annotation.name,
|
||||
closureRootNode
|
||||
)
|
||||
}
|
||||
}
|
||||
val funcSchemaBldr = FunctionSchema
|
||||
.newBuilder()
|
||||
.annotations(annotations: _*)
|
||||
.argumentDefinitions(arguments: _*)
|
||||
if (methodDef.isPrivate) {
|
||||
funcSchemaBldr.projectPrivate();
|
||||
}
|
||||
val funcSchema = funcSchemaBldr.build();
|
||||
new RuntimeFunction(
|
||||
callTarget,
|
||||
null,
|
||||
funcSchema
|
||||
)
|
||||
}
|
||||
|
||||
private def buildBuiltinFunction(
|
||||
fn: Function,
|
||||
expressionProcessor: ExpressionProcessor,
|
||||
methodDef: Method.Explicit,
|
||||
effectContext: Option[String],
|
||||
cons: Type,
|
||||
fullMethodDefName: String
|
||||
): Either[CompilerError, Option[RuntimeFunction]] = {
|
||||
// For builtin types that own the builtin method we only check that
|
||||
// the method has been registered during the initialization of builtins
|
||||
// and not attempt to register it in the scope (can't redefined methods).
|
||||
@ -539,146 +716,53 @@ class IrToTruffle(
|
||||
}
|
||||
}
|
||||
)
|
||||
case fn: Function =>
|
||||
val bodyBuilder =
|
||||
new expressionProcessor.BuildFunctionBody(
|
||||
fullMethodDefName,
|
||||
fn.arguments,
|
||||
fn.body,
|
||||
null,
|
||||
effectContext,
|
||||
true
|
||||
)
|
||||
|
||||
val operators = ".!$%&*+-/<>?^~\\="
|
||||
def isOperator(n: Name): Boolean = {
|
||||
n.name
|
||||
.chars()
|
||||
.allMatch(operators.indexOf(_) >= 0)
|
||||
}
|
||||
|
||||
val arguments = bodyBuilder.args()
|
||||
val rootNode =
|
||||
if (arguments.size == 2 && isOperator(methodDef.methodName)) {
|
||||
MethodRootNode.buildOperator(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
scopeBuilder.asModuleScope(),
|
||||
() => bodyBuilder.argsExpr._1(0),
|
||||
() => bodyBuilder.argsExpr._1(1),
|
||||
() => bodyBuilder.argsExpr._2,
|
||||
makeSection(scopeBuilder.getModule, methodDef.location),
|
||||
cons,
|
||||
methodDef.methodName.name
|
||||
private def getTypeAssociatedWithMethodDefinition(
|
||||
methodDef: Method.Explicit
|
||||
): Option[Type] = {
|
||||
methodDef.methodReference.typePointer match {
|
||||
case None =>
|
||||
Some(scopeAssociatedType)
|
||||
case Some(tpePointer) =>
|
||||
tpePointer
|
||||
.getMetadata(MethodDefinitions)
|
||||
.map { res =>
|
||||
res.target match {
|
||||
case binding @ BindingsMap.ResolvedType(_, _) =>
|
||||
asType(binding)
|
||||
case BindingsMap.ResolvedModule(module) =>
|
||||
asAssociatedType(module.unsafeAsModule())
|
||||
case BindingsMap.ResolvedConstructor(_, _) =>
|
||||
throw new CompilerError(
|
||||
"Impossible, should be caught by MethodDefinitions pass"
|
||||
)
|
||||
} else {
|
||||
MethodRootNode.build(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
scopeBuilder.asModuleScope(),
|
||||
() => bodyBuilder.bodyNode(),
|
||||
makeSection(scopeBuilder.getModule, methodDef.location),
|
||||
cons,
|
||||
methodDef.methodName.name
|
||||
case BindingsMap.ResolvedPolyglotSymbol(_, _) =>
|
||||
throw new CompilerError(
|
||||
"Impossible polyglot symbol, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
}
|
||||
val callTarget = rootNode.getCallTarget
|
||||
// build annotations
|
||||
val annotations =
|
||||
methodDef.getMetadata(GenericAnnotations).toVector.flatMap {
|
||||
meta =>
|
||||
meta.annotations
|
||||
.collect { case annotation: Name.GenericAnnotation =>
|
||||
val scopeElements = Seq(
|
||||
cons.getName,
|
||||
methodDef.methodName.name,
|
||||
annotation.name
|
||||
case BindingsMap.ResolvedPolyglotField(_, _) =>
|
||||
throw new CompilerError(
|
||||
"Impossible polyglot field, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
val scopeName =
|
||||
scopeElements.mkString(Constants.SCOPE_SEPARATOR)
|
||||
val scopeInfo = annotation
|
||||
.unsafeGetMetadata(
|
||||
AliasAnalysis,
|
||||
s"Missing scope information for annotation " +
|
||||
s"${annotation.name} of method " +
|
||||
scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)
|
||||
case _: BindingsMap.ResolvedModuleMethod =>
|
||||
throw new CompilerError(
|
||||
"Impossible module method here, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
.unsafeAs[AliasInfo.Scope.Root]
|
||||
val dataflowInfo = annotation.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Missing dataflow information for annotation " +
|
||||
s"${annotation.name} of method " +
|
||||
scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)
|
||||
case _: BindingsMap.ResolvedExtensionMethod =>
|
||||
throw new CompilerError(
|
||||
"Impossible static method here, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
val expressionProcessor = new ExpressionProcessor(
|
||||
scopeName,
|
||||
scopeInfo.graph,
|
||||
scopeInfo.graph.rootScope,
|
||||
dataflowInfo,
|
||||
methodDef.methodName.name
|
||||
)
|
||||
val expressionNode =
|
||||
expressionProcessor.run(annotation.expression, true)
|
||||
val closureName =
|
||||
s"<default::${expressionProcessor.scopeName}>"
|
||||
val closureRootNode = ClosureRootNode.build(
|
||||
language,
|
||||
expressionProcessor.scope,
|
||||
scopeBuilder.asModuleScope(),
|
||||
expressionNode,
|
||||
makeSection(
|
||||
scopeBuilder.getModule,
|
||||
annotation.location
|
||||
),
|
||||
closureName,
|
||||
true,
|
||||
false
|
||||
)
|
||||
new RuntimeAnnotation(
|
||||
annotation.name,
|
||||
closureRootNode
|
||||
case _: BindingsMap.ResolvedConversionMethod =>
|
||||
throw new CompilerError(
|
||||
"Impossible conversion method here, should be caught by MethodDefinitions pass."
|
||||
)
|
||||
}
|
||||
}
|
||||
val funcSchemaBldr = FunctionSchema
|
||||
.newBuilder()
|
||||
.annotations(annotations: _*)
|
||||
.argumentDefinitions(arguments: _*)
|
||||
if (methodDef.isPrivate) {
|
||||
funcSchemaBldr.projectPrivate();
|
||||
}
|
||||
val funcSchema = funcSchemaBldr.build();
|
||||
Right(
|
||||
Some(
|
||||
new RuntimeFunction(
|
||||
callTarget,
|
||||
null,
|
||||
funcSchema
|
||||
)
|
||||
)
|
||||
)
|
||||
case _ =>
|
||||
Left(
|
||||
new CompilerError(
|
||||
"Method bodies must be functions at the point of codegen."
|
||||
)
|
||||
)
|
||||
}
|
||||
function match {
|
||||
case Left(failure) =>
|
||||
throw failure
|
||||
case Right(Some(fun)) =>
|
||||
fun
|
||||
case x =>
|
||||
throw new IllegalStateException("Wrong state: " + x)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
private def registerConversions(module: Module): Unit = {
|
||||
val conversionDefs = module.bindings.collect {
|
||||
case conversion: definition.Method.Conversion =>
|
||||
conversion
|
||||
@ -754,7 +838,6 @@ class IrToTruffle(
|
||||
scopeBuilder.registerConversionMethod(toType, fromType, function)
|
||||
}
|
||||
})
|
||||
scopeBuilder.build()
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
Loading…
Reference in New Issue
Block a user