Enable conversion methods (#3177)

This commit is contained in:
Dmitry Bushev 2021-12-03 18:14:13 +03:00 committed by GitHub
parent 7239643046
commit 6a426c477a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 135 additions and 0 deletions

View File

@ -162,6 +162,10 @@ class IrToTruffle(
val methodDefs = module.bindings.collect {
case method: IR.Module.Scope.Definition.Method.Explicit => method
}
val conversionDefs = module.bindings.collect {
case conversion: IR.Module.Scope.Definition.Method.Conversion =>
conversion
}
// Register the imports in scope
imports.foreach {
@ -287,7 +291,80 @@ class IrToTruffle(
}
moduleScope.registerMethod(cons, methodDef.methodName.name, function)
}
})
// Register the conversion definitions in scope
conversionDefs.foreach(methodDef => {
val scopeInfo = methodDef
.unsafeGetMetadata(
AliasAnalysis,
s"Missing scope information for conversion " +
s"`${methodDef.typeName.name}.${methodDef.methodName.name}`."
)
.unsafeAs[AliasAnalysis.Info.Scope.Root]
val dataflowInfo = methodDef.unsafeGetMetadata(
DataflowAnalysis,
"Method definition missing dataflow information."
)
val consOpt =
methodDef.methodReference.typePointer
.getMetadata(MethodDefinitions)
.map { res =>
res.target match {
case BindingsMap.ResolvedModule(module) =>
module.unsafeAsModule().getScope.getAssociatedType
case BindingsMap.ResolvedConstructor(definitionModule, cons) =>
definitionModule
.unsafeAsModule()
.getScope
.getConstructors
.get(cons.name)
case BindingsMap.ResolvedPolyglotSymbol(_, _) =>
throw new CompilerError(
"Impossible polyglot symbol, should be caught by MethodDefinitions pass."
)
case _: BindingsMap.ResolvedMethod =>
throw new CompilerError(
"Impossible here, should be caught by MethodDefinitions pass."
)
}
}
consOpt.foreach { cons =>
val expressionProcessor = new ExpressionProcessor(
cons.getName ++ Constants.SCOPE_SEPARATOR ++ methodDef.methodName.name,
scopeInfo.graph,
scopeInfo.graph.rootScope,
dataflowInfo
)
val function = methodDef.body match {
case fn: IR.Function =>
val (body, arguments) =
expressionProcessor.buildFunctionBody(fn.arguments, fn.body)
val rootNode = MethodRootNode.build(
language,
expressionProcessor.scope,
moduleScope,
body,
makeSection(methodDef.location),
cons,
methodDef.methodName.name
)
val callTarget = Truffle.getRuntime.createCallTarget(rootNode)
new RuntimeFunction(
callTarget,
null,
new FunctionSchema(arguments: _*)
)
case _ =>
throw new CompilerError(
"Conversion bodies must be functions at the point of codegen."
)
}
moduleScope.registerMethod(cons, methodDef.methodName.name, function)
}
})
}

View File

@ -215,6 +215,64 @@ class RuntimeInstrumentTest
)
}
it should "instrument conversion methods" in {
val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID()
val moduleName = "Enso_Test.Test.Main"
val fooTypeName = s"$moduleName.Foo"
val metadata = new Metadata
val mainBody = metadata.addItem(52, 12)
val code =
"""type Foo
|type Bar
|
|Foo.from (_ : Bar) = Foo
|
|main = Foo.from Bar
|""".stripMargin.linesIterator.mkString("\n")
val contents = metadata.appendToCode(code)
val mainFile = context.writeMain(contents)
// create context
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
context.receive shouldEqual Some(
Api.Response(requestId, Api.CreateContextResponse(contextId))
)
// Open the new file
context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents))
)
context.receiveNone shouldEqual None
// push main
context.send(
Api.Request(
requestId,
Api.PushContextRequest(
contextId,
Api.StackItem.ExplicitCall(
Api.MethodPointer(moduleName, "Enso_Test.Test.Main", "main"),
None,
Vector()
)
)
)
)
context.receive(3) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)),
TestMessages.update(
contextId,
mainBody,
fooTypeName,
Api.MethodPointer(moduleName, fooTypeName, "from")
),
context.executionComplete(contextId)
)
}
it should "instrument expressions" in {
val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID()