Skip to content

Commit

Permalink
Use fn... to reference argumentless module function
Browse files Browse the repository at this point in the history
  • Loading branch information
JaroslavTulach committed Jan 24, 2025
1 parent 78febd5 commit e4ec18e
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -340,26 +340,41 @@ case object GlobalNames extends IRPass {
)
)
processedFun.getMetadata(this) match {
case Some(Resolution(ResolvedModuleMethod(mod, _))) if !isLocalVar(fun) =>
val self = freshNameSupply
.newName()
.updateMetadata(
new MetadataPair(
this,
BindingsMap.Resolution(
BindingsMap.ResolvedModule(mod)
case Some(Resolution(resMethod @ ResolvedModuleMethod(mod, _)))
if !isLocalVar(fun) =>
if (app.hasDefaultsSuspended && app.arguments.isEmpty) {
app
.updateMetadata(
new MetadataPair(
this,
BindingsMap.Resolution(resMethod)
)
)

} else {
val self = freshNameSupply
.newName()
.updateMetadata(
new MetadataPair(
this,
BindingsMap.Resolution(
BindingsMap.ResolvedModule(mod)
)
)
)
val selfArg =
new CallArgument.Specified(
None,
self,
true,
identifiedLocation = null
)
processedFun.passData.remove(this) // Necessary for IrToTruffle
app.copy(
function = processedFun,
arguments = selfArg :: processedArgs
)
val selfArg =
new CallArgument.Specified(
None,
self,
true,
identifiedLocation = null
)
processedFun.passData.remove(this) // Necessary for IrToTruffle
app.copy(function = processedFun, arguments = selfArg :: processedArgs)
}
case _ =>
app.copy(function = processedFun, arguments = processedArgs)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.enso.interpreter.test.semantic;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import com.oracle.truffle.api.interop.InteropLibrary;
import java.nio.file.Paths;
import java.util.Map;
import java.util.logging.Level;
import org.enso.common.RuntimeOptions;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.test.utils.ContextUtils;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Language;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.io.IOAccess;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class FunctionIdentityTest {

private Context ctx;

@Before
public void initContext() {
ctx =
Context.newBuilder()
.allowExperimentalOptions(true)
.option(
RuntimeOptions.LANGUAGE_HOME_OVERRIDE,
Paths.get("../../distribution/component").toFile().getAbsolutePath())
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
.logHandler(System.err)
.allowExperimentalOptions(true)
.allowIO(IOAccess.ALL)
.allowAllAccess(true)
.build();

var engine = ctx.getEngine();
Map<String, Language> langs = engine.getLanguages();
Assert.assertNotNull("Enso found: " + langs, langs.get("enso"));
}

@After
public void disposeContext() {
ctx.close();
ctx = null;
}

@Test
public void functionWithArgIdentity() throws Exception {
var rawCode = """
am_i_me _ = am_i_me...
""";
assertFunctionIdentity(rawCode, "Am_I_Me_With_Arg");
}

@Test
public void functionIdentity() throws Exception {
var rawCode = """
am_i_me = am_i_me...
""";
assertFunctionIdentity(rawCode, "Am_I_Me");
}

private void assertFunctionIdentity(String code, String moduleName) throws Exception {
var src = Source.newBuilder("enso", code, moduleName + ".enso").build();
var module = ctx.eval(src);
var fn = module.invokeMember("eval_expression", "am_i_me").execute(0);

assertTrue("fn: " + fn, fn.canExecute());

var rawFn = ContextUtils.unwrapValue(ctx, fn);
assertTrue("is Function: " + rawFn, rawFn instanceof Function);

var iop = InteropLibrary.getUncached();
assertEquals(moduleName + ".am_i_me", iop.getExecutableName(rawFn));
assertTrue("Has location", iop.hasSourceLocation(rawFn));
var loc = iop.getSourceLocation(rawFn);
assertNotNull("Location found", loc);
assertEquals(
"am_i_me function definition is on the first line",
code.split("\n")[0],
loc.getCharacters().toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,26 @@ boolean isExecutable() {
return true;
}

@ExportMessage
boolean hasSourceLocation() {
return getSourceSection() != null;
}

@ExportMessage
SourceSection getSourceLocation() {
return callTarget.getRootNode().getSourceSection();
}

@ExportMessage
boolean hasExecutableName() {
return getName() != null;
}

@ExportMessage
String getExecutableName() {
return this.getName();
}

/**
* A class representing the executable behaviour of the function.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2028,9 +2028,15 @@ class IrToTruffle(
asScope(symbol.module.unsafeAsModule())
.getPolyglotSymbolSupplier(name)
LazyObjectNode.build(name, s)
case BindingsMap.ResolvedModuleMethod(_, method) =>
throw new CompilerError(
s"Impossible here, module method ${method.name} should be caught when translating application"
case BindingsMap.ResolvedModuleMethod(module, method) =>
LazyObjectNode.build(
method.name,
() => {
val typ = asAssociatedType(module.unsafeAsModule())
val scope = asScope(module.unsafeAsModule())
val fn = scope.getMethodForType(typ, method.name)
fn
}
)
case BindingsMap.ResolvedExtensionMethod(_, staticMethod) =>
throw new CompilerError(
Expand Down

0 comments on commit e4ec18e

Please sign in to comment.