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:
Radosław Waśko 2024-07-18 14:14:11 +02:00 committed by GitHub
parent 473a51cee7
commit 4e310d723d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -41,10 +41,12 @@ import org.enso.compiler.core.ir.expression.{
Operator, Operator,
Section 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.{ResolvedConstructor, ResolvedModule}
import org.enso.compiler.data.{BindingsMap, CompilerConfig} import org.enso.compiler.data.{BindingsMap, CompilerConfig}
import org.enso.compiler.exception.BadPatternMatch import org.enso.compiler.exception.BadPatternMatch
import org.enso.compiler.pass.analyse.alias.Graph.{Scope => AliasScope} 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.{ import org.enso.compiler.pass.analyse.{
AliasAnalysis, AliasAnalysis,
BindingAnalysis, BindingAnalysis,
@ -193,6 +195,18 @@ class IrToTruffle(
"No binding analysis at the point of codegen." "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 => bindingsMap.getDirectlyExportedModules.foreach { exportedMod =>
val exportedRuntimeMod = exportedMod.module.module.unsafeAsModule() val exportedRuntimeMod = exportedMod.module.module.unsafeAsModule()
scopeBuilder.addExport( scopeBuilder.addExport(
@ -200,11 +214,7 @@ class IrToTruffle(
) )
} }
val importDefs = module.imports private def registerModuleImports(bindingsMap: BindingsMap): Unit =
val methodDefs = module.bindings.collect {
case method: definition.Method.Explicit => method
}
bindingsMap.resolvedImports.foreach { imp => bindingsMap.resolvedImports.foreach { imp =>
imp.targets.foreach { imp.targets.foreach {
case _: BindingsMap.ResolvedType => case _: BindingsMap.ResolvedType =>
@ -222,8 +232,8 @@ class IrToTruffle(
} }
} }
// Register the imports in scope private def registerPolyglotImports(module: Module): Unit =
importDefs.foreach { module.imports.foreach {
case poly @ imports.Polyglot(i: imports.Polyglot.Java, _, _, _, _) => case poly @ imports.Polyglot(i: imports.Polyglot.Java, _, _, _, _) =>
var hostSymbol = context.lookupJavaClass(i.getJavaName) var hostSymbol = context.lookupJavaClass(i.getJavaName)
if (hostSymbol == null) { if (hostSymbol == null) {
@ -240,6 +250,7 @@ class IrToTruffle(
case _: Error => case _: Error =>
} }
private def registerTypeDefinitions(module: Module): Unit = {
val typeDefs = module.bindings.collect { case tp: Definition.Type => tp } val typeDefs = module.bindings.collect { case tp: Definition.Type => tp }
typeDefs.foreach { tpDef => typeDefs.foreach { tpDef =>
// Register the atoms and their constructors in scope // Register the atoms and their constructors in scope
@ -250,107 +261,120 @@ class IrToTruffle(
atomConstructors atomConstructors
.zip(atomDefs) .zip(atomDefs)
.foreach { case (atomCons, atomDefn) => .foreach { case (atomCons, atomDefn) =>
val scopeInfo = atomDefn registerAtomConstructor(tpDef, atomCons, atomDefn)
.unsafeGetMetadata(
AliasAnalysis,
"No root scope on an atom definition."
)
.unsafeAs[AliasInfo.Scope.Root]
val dataflowInfo = atomDefn.unsafeGetMetadata(
DataflowAnalysis,
"No dataflow information associated with an atom."
)
val localScope = new LocalScope(
None,
scopeInfo.graph,
scopeInfo.graph.rootScope,
dataflowInfo
)
val argFactory =
new DefinitionArgumentProcessor(
scope = localScope,
initialName = "Type " + tpDef.name
)
val argDefs =
new Array[ArgumentDefinition](atomDefn.arguments.size)
val argumentExpressions =
new ArrayBuffer[(RuntimeExpression, RuntimeExpression)]
for (idx <- atomDefn.arguments.indices) {
val unprocessedArg = atomDefn.arguments(idx)
val checkNode = checkAsTypes(unprocessedArg)
val arg = argFactory.run(unprocessedArg, idx, checkNode)
val occInfo = unprocessedArg
.unsafeGetMetadata(
AliasAnalysis,
"No occurrence on an argument definition."
)
.unsafeAs[AliasInfo.Occurrence]
val slotIdx = localScope.getVarSlotIdx(occInfo.id)
argDefs(idx) = arg
val readArg =
ReadArgumentNode.build(
idx,
arg.getDefaultValue.orElse(null),
checkNode
)
val assignmentArg = AssignmentNode.build(readArg, slotIdx)
val argRead =
ReadLocalVariableNode.build(new FramePointer(0, slotIdx))
argumentExpressions.append((assignmentArg, argRead))
}
val (assignments, reads) = argumentExpressions.unzip
// build annotations
val annotations = atomDefn.annotations.map { annotation =>
val scopeElements = Seq(
tpDef.name.name,
atomDefn.name.name,
annotation.name
)
val scopeName =
scopeElements.mkString(Constants.SCOPE_SEPARATOR)
val expressionProcessor = new ExpressionProcessor(
scopeName,
scopeInfo.graph,
scopeInfo.graph.rootScope,
dataflowInfo,
atomDefn.name.name
)
val expressionNode =
expressionProcessor.run(annotation.expression, true)
val closureName = s"<default::$scopeName>"
val closureRootNode = ClosureRootNode.build(
language,
expressionProcessor.scope,
scopeBuilder.asModuleScope(),
expressionNode,
makeSection(scopeBuilder.getModule, annotation.location),
closureName,
true,
false
)
new RuntimeAnnotation(annotation.name, closureRootNode)
}
if (!atomCons.isInitialized) {
atomCons.initializeFields(
language,
makeSection(scopeBuilder.getModule, atomDefn.location),
localScope,
scopeBuilder,
assignments.toArray,
reads.toArray,
annotations.toArray,
argDefs: _*
)
}
} }
asType.generateGetters(language) asType.generateGetters(language)
} }
}
private def registerAtomConstructor(
tpDef: Definition.Type,
atomCons: AtomConstructor,
atomDefn: Definition.Data
): Unit = {
val scopeInfo = atomDefn
.unsafeGetMetadata(
AliasAnalysis,
"No root scope on an atom definition."
)
.unsafeAs[AliasInfo.Scope.Root]
val dataflowInfo = atomDefn.unsafeGetMetadata(
DataflowAnalysis,
"No dataflow information associated with an atom."
)
val localScope = new LocalScope(
None,
scopeInfo.graph,
scopeInfo.graph.rootScope,
dataflowInfo
)
val argFactory =
new DefinitionArgumentProcessor(
scope = localScope,
initialName = "Type " + tpDef.name
)
val argDefs =
new Array[ArgumentDefinition](atomDefn.arguments.size)
val argumentExpressions =
new ArrayBuffer[(RuntimeExpression, RuntimeExpression)]
for (idx <- atomDefn.arguments.indices) {
val unprocessedArg = atomDefn.arguments(idx)
val checkNode = checkAsTypes(unprocessedArg)
val arg = argFactory.run(unprocessedArg, idx, checkNode)
val occInfo = unprocessedArg
.unsafeGetMetadata(
AliasAnalysis,
"No occurrence on an argument definition."
)
.unsafeAs[AliasInfo.Occurrence]
val slotIdx = localScope.getVarSlotIdx(occInfo.id)
argDefs(idx) = arg
val readArg =
ReadArgumentNode.build(
idx,
arg.getDefaultValue.orElse(null),
checkNode
)
val assignmentArg = AssignmentNode.build(readArg, slotIdx)
val argRead =
ReadLocalVariableNode.build(new FramePointer(0, slotIdx))
argumentExpressions.append((assignmentArg, argRead))
}
val (assignments, reads) = argumentExpressions.unzip
// build annotations
val annotations = atomDefn.annotations.map { annotation =>
val scopeElements = Seq(
tpDef.name.name,
atomDefn.name.name,
annotation.name
)
val scopeName =
scopeElements.mkString(Constants.SCOPE_SEPARATOR)
val expressionProcessor = new ExpressionProcessor(
scopeName,
scopeInfo.graph,
scopeInfo.graph.rootScope,
dataflowInfo,
atomDefn.name.name
)
val expressionNode =
expressionProcessor.run(annotation.expression, true)
val closureName = s"<default::$scopeName>"
val closureRootNode = ClosureRootNode.build(
language,
expressionProcessor.scope,
scopeBuilder.asModuleScope(),
expressionNode,
makeSection(scopeBuilder.getModule, annotation.location),
closureName,
true,
false
)
new RuntimeAnnotation(annotation.name, closureRootNode)
}
if (!atomCons.isInitialized) {
atomCons.initializeFields(
language,
makeSection(scopeBuilder.getModule, atomDefn.location),
localScope,
scopeBuilder,
assignments.toArray,
reads.toArray,
annotations.toArray,
argDefs: _*
)
}
}
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 => { methodDefs.foreach(methodDef => {
val scopeInfo = methodDef val scopeInfo = methodDef
.unsafeGetMetadata( .unsafeGetMetadata(
@ -380,45 +404,7 @@ class IrToTruffle(
.flatMap(sig => getContext(sig.signature)) .flatMap(sig => getContext(sig.signature))
val declaredConsOpt = val declaredConsOpt =
methodDef.methodReference.typePointer match { getTypeAssociatedWithMethodDefinition(methodDef)
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."
)
}
}
}
val consOpt = declaredConsOpt.map { c => val consOpt = declaredConsOpt.map { c =>
if (methodDef.isStatic) { if (methodDef.isStatic) {
@ -441,244 +427,342 @@ class IrToTruffle(
cons, cons,
methodDef.methodName.name, methodDef.methodName.name,
() => { () => {
val function = methodDef.body match { buildFunction(
case fn: Function if isBuiltinMethod(fn.body) => methodDef,
// For builtin types that own the builtin method we only check that effectContext,
// the method has been registered during the initialization of builtins cons,
// and not attempt to register it in the scope (can't redefined methods). fullMethodDefName,
// For non-builtin types (or modules) that own the builtin method expressionProcessor
// we have to look up the function and register it in the scope. )
// Static wrappers for instance methods have to be registered always.
val fullMethodName = methodDef.body
.asInstanceOf[Function.Lambda]
.body
.asInstanceOf[Literal.Text]
val builtinNameElements = fullMethodName.text.split('.')
if (builtinNameElements.length != 2) {
throw new CompilerError(
s"Unknown builtin method ${fullMethodName.text}, probably should be '$fullMethodDefName?'"
)
}
val methodName = builtinNameElements(1)
val methodOwnerName = builtinNameElements(0)
val staticWrapper = methodDef.isStaticWrapperForInstanceMethod
val builtinFunction = context.getBuiltins
.getBuiltinFunction(
methodOwnerName,
methodName,
language,
staticWrapper
)
builtinFunction.toScala
.map(Some(_))
.toRight(
new CompilerError(
s"Unable to find Truffle Node for method ${cons.getName}.${methodDef.methodName.name}"
)
)
.left
.flatMap { l =>
// Builtin Types Number and Integer have methods only for documentation purposes
val number = context.getBuiltins.number()
val ok =
staticWrapper && (cons == number.getNumber.getEigentype || cons == number.getInteger.getEigentype) ||
!staticWrapper && (cons == number.getNumber || cons == number.getInteger)
if (ok) Right(None)
else Left(l)
}
.map(fOpt =>
fOpt.map { m =>
if (m.isAutoRegister) {
val irFunctionArgumentsCount = fn.arguments.length
val builtinArgumentsCount =
m.getFunction.getSchema.getArgumentsCount
if (irFunctionArgumentsCount != builtinArgumentsCount) {
val irFunctionArguments =
fn.arguments.map(_.name.name).mkString(",")
val builtinArguments =
m.getFunction.getSchema.getArgumentInfos
.map(_.getName)
.mkString(",")
throw new CompilerError(
s"Wrong number of arguments provided in the definition of builtin function ${cons.getName}.${methodDef.methodName.name}. " +
s"[$irFunctionArguments] vs [$builtinArguments]"
)
}
val bodyBuilder =
new expressionProcessor.BuildFunctionBody(
m.getFunction.getName,
fn.arguments,
fn.body,
null,
effectContext,
true
)
val builtinRootNode =
m.getFunction.getCallTarget.getRootNode
.asInstanceOf[BuiltinRootNode]
builtinRootNode
.setModuleName(scopeBuilder.getModule.getName)
builtinRootNode.setTypeName(cons.getQualifiedName)
val funcSchemaBldr = FunctionSchema
.newBuilder()
.argumentDefinitions(bodyBuilder.args(): _*)
if (methodDef.isPrivate) {
funcSchemaBldr.projectPrivate();
}
val funcSchema = funcSchemaBldr.build()
new RuntimeFunction(
m.getFunction.getCallTarget,
null,
funcSchema
)
} else {
m.getFunction
}
}
)
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
)
} 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[AliasInfo.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();
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 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).
// For non-builtin types (or modules) that own the builtin method
// we have to look up the function and register it in the scope.
// Static wrappers for instance methods have to be registered always.
val fullMethodName = methodDef.body
.asInstanceOf[Function.Lambda]
.body
.asInstanceOf[Literal.Text]
val builtinNameElements = fullMethodName.text.split('.')
if (builtinNameElements.length != 2) {
throw new CompilerError(
s"Unknown builtin method ${fullMethodName.text}, probably should be '$fullMethodDefName?'"
)
}
val methodName = builtinNameElements(1)
val methodOwnerName = builtinNameElements(0)
val staticWrapper = methodDef.isStaticWrapperForInstanceMethod
val builtinFunction = context.getBuiltins
.getBuiltinFunction(
methodOwnerName,
methodName,
language,
staticWrapper
)
builtinFunction.toScala
.map(Some(_))
.toRight(
new CompilerError(
s"Unable to find Truffle Node for method ${cons.getName}.${methodDef.methodName.name}"
)
)
.left
.flatMap { l =>
// Builtin Types Number and Integer have methods only for documentation purposes
val number = context.getBuiltins.number()
val ok =
staticWrapper && (cons == number.getNumber.getEigentype || cons == number.getInteger.getEigentype) ||
!staticWrapper && (cons == number.getNumber || cons == number.getInteger)
if (ok) Right(None)
else Left(l)
}
.map(fOpt =>
fOpt.map { m =>
if (m.isAutoRegister) {
val irFunctionArgumentsCount = fn.arguments.length
val builtinArgumentsCount =
m.getFunction.getSchema.getArgumentsCount
if (irFunctionArgumentsCount != builtinArgumentsCount) {
val irFunctionArguments =
fn.arguments.map(_.name.name).mkString(",")
val builtinArguments =
m.getFunction.getSchema.getArgumentInfos
.map(_.getName)
.mkString(",")
throw new CompilerError(
s"Wrong number of arguments provided in the definition of builtin function ${cons.getName}.${methodDef.methodName.name}. " +
s"[$irFunctionArguments] vs [$builtinArguments]"
)
}
val bodyBuilder =
new expressionProcessor.BuildFunctionBody(
m.getFunction.getName,
fn.arguments,
fn.body,
null,
effectContext,
true
)
val builtinRootNode =
m.getFunction.getCallTarget.getRootNode
.asInstanceOf[BuiltinRootNode]
builtinRootNode
.setModuleName(scopeBuilder.getModule.getName)
builtinRootNode.setTypeName(cons.getQualifiedName)
val funcSchemaBldr = FunctionSchema
.newBuilder()
.argumentDefinitions(bodyBuilder.args(): _*)
if (methodDef.isPrivate) {
funcSchemaBldr.projectPrivate();
}
val funcSchema = funcSchemaBldr.build()
new RuntimeFunction(
m.getFunction.getCallTarget,
null,
funcSchema
)
} else {
m.getFunction
}
}
)
}
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"
)
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."
)
}
}
}
}
private def registerConversions(module: Module): Unit = {
val conversionDefs = module.bindings.collect { val conversionDefs = module.bindings.collect {
case conversion: definition.Method.Conversion => case conversion: definition.Method.Conversion =>
conversion conversion
@ -754,7 +838,6 @@ class IrToTruffle(
scopeBuilder.registerConversionMethod(toType, fromType, function) scopeBuilder.registerConversionMethod(toType, fromType, function)
} }
}) })
scopeBuilder.build()
} }
// ========================================================================== // ==========================================================================