Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infer method calls on known types and warn about nonexistent methods #11399

Open
wants to merge 137 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
2715738
rename pass
radeusgd Apr 27, 2024
c1d4cc1
WIP: find types from checked signatures
radeusgd Apr 27, 2024
b284ec5
rename CompilerTest -> ParserTest
radeusgd Apr 27, 2024
7968622
refactor: move some common methods to separate class to allow for reuse
radeusgd Apr 27, 2024
f21b783
add a test for the type extraction
radeusgd Apr 27, 2024
a1bf4f7
fix test
radeusgd Apr 27, 2024
28626fa
WIP tests
radeusgd May 2, 2024
9b5a87d
tests for methods
radeusgd May 2, 2024
f626367
add a test verifying return-type check on member methods - to test my…
radeusgd May 6, 2024
8aeb690
add a test that finds the cause of issue: FORCE node makes the ascrip…
radeusgd May 6, 2024
5c61beb
fix resolution of return types in type signatures
radeusgd May 6, 2024
f5ca4af
adding tests for member method calls
radeusgd May 6, 2024
435cd0e
find the right place to resolve calls
radeusgd May 6, 2024
8e95c78
use interpreter context to be able to use imports in the type inferen…
radeusgd May 10, 2024
218efcd
javafmt
radeusgd May 10, 2024
7594894
update tests
radeusgd May 10, 2024
9a40731
fix test
radeusgd May 11, 2024
215a91f
WIP
radeusgd May 13, 2024
f2b3dd7
fix compilation (stub)
radeusgd Jun 13, 2024
273687d
better message in test
radeusgd Jun 13, 2024
ea15ebc
WIP: StaticModuleScope
radeusgd Jun 13, 2024
cafc96d
WIP: StaticModuleScope 2
radeusgd Jun 14, 2024
730e3b9
WIP
radeusgd Jun 15, 2024
2aa0377
checkpoint
radeusgd Jun 15, 2024
e39f248
wiring the StaticModuleScopeAnalysis pass with rest of the system
radeusgd Jun 15, 2024
da82e47
formatting
radeusgd Jun 15, 2024
52ba2dd
debugging
radeusgd Jun 15, 2024
5152227
WIP: workaround for static methods on module?
radeusgd Jun 15, 2024
b7d0fef
debugging
radeusgd Jun 17, 2024
94d7323
debug
radeusgd Jun 17, 2024
042edfe
WIP: test
radeusgd Jun 17, 2024
7e7b977
resolving static module methods works
radeusgd Jun 27, 2024
44bfa7d
get rid of unnecessary parentheses in type string
radeusgd Jun 27, 2024
beba64d
javafmt
radeusgd Jun 27, 2024
8e58c92
ensure that test modules are registered in tests
radeusgd Jun 27, 2024
167f9e3
no such method tests
radeusgd Jun 28, 2024
5f2c4aa
member method call through static syntax
radeusgd Jun 28, 2024
02e8275
remove some prints
radeusgd Jun 28, 2024
448c8b2
test calling static method on member
radeusgd Jun 28, 2024
4cdd9da
WIP: static syntax for member methods
radeusgd Jul 5, 2024
d03cba3
fix
radeusgd Jul 6, 2024
64cd1b6
type hierarchy, reporting no such method
radeusgd Jul 6, 2024
5b23120
fix error locations, less logs
radeusgd Jul 6, 2024
23a3828
javafmt, add pass
radeusgd Jul 6, 2024
25f4560
heisenbug?!
radeusgd Jul 6, 2024
4573289
change order of compiler passes to have needed data available
radeusgd Jul 8, 2024
5a4e057
remove debug print
radeusgd Jul 8, 2024
b21f603
adjust missing builtin
radeusgd Jul 8, 2024
c56c347
fix static call syntax of member methods by correctly infrring their …
radeusgd Jul 12, 2024
2143368
add test for future
radeusgd Jul 12, 2024
e2f30b2
resolving Self type to the actual type
radeusgd Jul 12, 2024
22db8a6
fix test - metadata is now only attached to bindings
radeusgd Jul 12, 2024
f6b4638
nit
radeusgd Jul 12, 2024
b98be17
add test for fields access
radeusgd Jul 12, 2024
b2c75dc
WIP test for inter-module definitions
radeusgd Jul 12, 2024
7cfd7c4
WIP: debugging calling methods from different module
radeusgd Jul 12, 2024
fb5517f
adjust warning message
radeusgd Jul 12, 2024
da23709
adjust warning message, and other stuff
radeusgd Jul 12, 2024
9dc1268
checkpoint
radeusgd Jul 12, 2024
aa134ab
fix a test
radeusgd Jul 25, 2024
5181827
add a test - even if Any is not imported we should know its base meth…
radeusgd Jul 25, 2024
157787d
WIP
radeusgd Jul 25, 2024
0c202e9
fix indentation (?)
radeusgd Jul 25, 2024
44a4fd0
test local extension method
radeusgd Jul 25, 2024
0e932f4
inferring field getters
radeusgd Jul 26, 2024
90fd53a
fixes after rebase
radeusgd Aug 10, 2024
177e53a
javafmt
radeusgd Aug 10, 2024
6bb65c1
update links in doc
radeusgd Aug 12, 2024
9df01ef
very basic registering of imports
radeusgd Aug 12, 2024
2cb3fb6
WIP
radeusgd Aug 12, 2024
57b6208
WIP
radeusgd Aug 13, 2024
70cf5de
basic imports work
radeusgd Aug 13, 2024
6daf829
javafmt
radeusgd Aug 13, 2024
016d3e1
checkpoint
radeusgd Aug 13, 2024
46e42dd
hardcode builtins for Any
radeusgd Aug 13, 2024
aa4da65
add missing builtin method to make resolution checker happy
radeusgd Aug 13, 2024
7d655a4
figuring out resolution on Functions and duplicated imports?
radeusgd Aug 13, 2024
f90a096
add missing builtins
radeusgd Aug 13, 2024
6b621f8
remove debug print to avoid spam
radeusgd Aug 13, 2024
6a2289e
fix sigs
radeusgd Aug 13, 2024
baf4a97
fix how we find the package repo (before it was missing in some paths…
radeusgd Aug 13, 2024
34ef68b
WIP: resolving Type 'call' on module - phase 1 not report it as error…
radeusgd Aug 13, 2024
6bf74aa
Merge branch 'develop' into wip/radeusgd/9812-infer-method-calls
radeusgd Oct 22, 2024
d936281
javafmt
radeusgd Oct 22, 2024
4918207
get it to compile
radeusgd Oct 22, 2024
5dbc13a
fix ids after merge
radeusgd Oct 22, 2024
ef3daa0
javafmt once more
radeusgd Oct 22, 2024
bce8508
fixing conflicts, removing empty files
radeusgd Oct 22, 2024
237af09
moved classes to fix compilation
radeusgd Oct 22, 2024
1d25d08
fix NPE in test
radeusgd Oct 22, 2024
855b621
use right getter
radeusgd Oct 22, 2024
68555a5
mark private
radeusgd Oct 22, 2024
990f32f
try using a more random hash merge
radeusgd Oct 22, 2024
38c9f78
add some missing registrations
radeusgd Oct 22, 2024
1563397
if --no-ir-cache is set, --compile will not save caches - it will jus…
radeusgd Oct 22, 2024
d9db891
lower log level
radeusgd Oct 22, 2024
7719e3e
Merge branch 'develop' into wip/radeusgd/9812-infer-method-calls
radeusgd Oct 23, 2024
a912ef4
trying to look up all exported methods
radeusgd Oct 23, 2024
6eed3eb
Merge branch 'develop' into wip/radeusgd/9812-infer-method-calls
radeusgd Oct 24, 2024
ef9095a
make tests compile
radeusgd Oct 24, 2024
bff9a84
add a test for re-exports
radeusgd Oct 24, 2024
fb52dcc
fix re export resolution
radeusgd Oct 24, 2024
dd0b18b
find in imports: keep logic in one place
radeusgd Oct 24, 2024
33a7fac
more tests but ignored for now
radeusgd Oct 24, 2024
131116d
use Builder for StaticModuleScope
radeusgd Oct 24, 2024
981a202
doc
radeusgd Oct 24, 2024
9b43442
shape for common method resolution
radeusgd Oct 24, 2024
4b87f76
stub
radeusgd Oct 25, 2024
57e0859
add missing builtin to micro-distribution
radeusgd Oct 25, 2024
7794eee
use common method resolution algorithm in compiler
radeusgd Oct 25, 2024
60fff64
fix brackets in tests after improving toString
radeusgd Oct 25, 2024
436b660
add missing builtin, missing arg
radeusgd Oct 25, 2024
383e2ff
use common algorithm in runtime method resolution
radeusgd Oct 25, 2024
f90f4a2
`private` causes Private_Access errors - out of scope of this PR, so …
radeusgd Oct 25, 2024
6519fc1
Merge branch 'develop' into wip/radeusgd/9812-infer-method-calls
radeusgd Oct 25, 2024
a437c3e
fix after merge
radeusgd Oct 25, 2024
e994d0c
move to better location
radeusgd Oct 25, 2024
0aacaf9
WIP trying to extract common logic
radeusgd Oct 25, 2024
ae5dd11
WIP 2
radeusgd Oct 25, 2024
fc88957
integrate the common logic alg with IrToTruffle
radeusgd Oct 25, 2024
efadb43
WIP some cleanup in missing arg, starting work on static
radeusgd Oct 25, 2024
1b5ffc2
common parts in static module scope analysis
radeusgd Oct 25, 2024
1462e12
make it work
radeusgd Oct 28, 2024
1913402
fix original common code - there was a typo...
radeusgd Oct 28, 2024
eb9988a
doc
radeusgd Oct 28, 2024
eb8f69e
doc
radeusgd Oct 28, 2024
13c75b0
more docs
radeusgd Oct 28, 2024
b7690d5
do not log in tests
radeusgd Oct 28, 2024
457a63a
logger
radeusgd Oct 28, 2024
e09047d
remove stale todo
radeusgd Oct 28, 2024
894dabc
common getExportedMethod
radeusgd Oct 28, 2024
5f6bf2e
but now properly
radeusgd Oct 28, 2024
113eec3
common logic for conversions too
radeusgd Oct 28, 2024
5be3b82
remove AtomType stub - it was not finished - to be re-added in next i…
radeusgd Oct 28, 2024
4a415cc
Merge branch 'develop' into wip/radeusgd/9812-infer-method-calls
radeusgd Oct 29, 2024
3e78eb7
remove assert
radeusgd Oct 29, 2024
8d060ca
make it okay to miss a method pointer - just return null
radeusgd Oct 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ type Comparable

new value:Any comparator:Any -> Comparable = Comparable.By value comparator

## PRIVATE
less_than_builtin : Any -> Any -> Boolean | Nothing
less_than_builtin = @Builtin_Method "Comparable.less_than_builtin"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this method. @Builtin_Methods are supposed to be only in private modules. Moreover there already is such a less_than_builtin in Ordering_Helpers.enso.

Copy link
Member Author

@radeusgd radeusgd Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, this method is indeed wrong, as I don't see a Comparable.less_than_builtin builtin in Java.

It was probably an artifact from some merges that happened along the way (or just my oversight). I'll remove this one.


## PRIVATE
Comparable.from (that:Any) = Comparable.new that Default_Comparator

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ type Default_Comparator
## PRIVATE
hash : Number -> Integer
hash x = Default_Comparator.hash_builtin x

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary changes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just trying to apply consistent formatting.

## PRIVATE
hash_builtin x = @Builtin_Method "Default_Comparator.hash_builtin"

## PRIVATE
less_than_builtin left right = @Builtin_Method "Default_Comparator.less_than_builtin"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ type Project_Description
namespace : Text
namespace self = self.ns

## PRIVATE
enso_project_builtin module = @Builtin_Method "Project_Description.enso_project_builtin"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't put Builtin_Methods into non-private modules.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@radeusgd has a good point. The corresponding builtin method is already defined as EnsoProjectNode. Thus, this code does not introduce any changes. It seems that BuiltinFunction.isAutoRegister makes it possible to defined a builtin method in Java without any shadow definition in Enso code. I think having these kind of shadow definitions is beneficial, as we can immediately see all the definitions of builtin methods on a type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's how auto register was supposed to work.


## ICON enso_icon
Returns the Enso project description for the project that the engine was
executed with, i.e., the project that contains the `main` method, or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,12 @@ type File
to_display_text : Text
to_display_text self = self.to_text

## PRIVATE
copy_builtin self target options = @Builtin_Method "File.copy_builtin"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing all these (undesirable) @Builtin_Methods changes, I wonder how are they related to type inference?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no changes to builtin methods structure.

I'm only reproducing in Enso code the structure that has already been there in the builtins. That is - we already were having calls to File.copy_builtin or Comparable.less_than_builtin in the code, they were just lacking the related definitions.

If that structure is undesirable, we should restructure the builtins, but that is not really in the scope of the PR. But if you will not allow me to merge it without that, I will probably be forced to do this unrelated change.

I wonder how are they related to type inference?

I've added checking of method calls. What methods are available on an object was taken from the type definitions. If a builtin method was called e.g. File.copy_builtin but there was no copy_builtin defined on File, my type inference was giving warnings about calling nonexstent methods. I don't think builtins shall be a special case (apart from a naming convention I cannot easily tell if a method is a builtin or doesn't exist). Most of our builtins already had such 'shadow definitions', there was just a few that were lacking and I've added these missing ones. See for example, File.input_stream_builtin - it's been there for a long time. I think we should do a proper refactor of builtins to move them into private modules. But that's the #6282 ticket.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the other hand, these changes are not absolutely required for the type inference changes. They are there to make the tests pass, but I can @Ignore a few tests and revert these changes so that we can handle them separately. Maybe I should have done them as a separate PR like with #11422

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like these kind of shadow definitions of builtin methods. They don't (at least they should not) introduce any changes (that is, they don't introduce any new builtins) and they make it easy to see which builtin methods are defined on a type. It may be worth revisiting BuiltinMethod.autoRegister annotation argument.

See my other comment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a builtin method was called e.g. File.copy_builtin but there was no copy_builtin defined on File, my type inference was giving warnings about calling nonexstent methods.

I see. That's indeed related.

I don't think builtins shall be a special case

Builtin methods are special case! They are not behaving as normal methods.

we should do a proper refactor of builtins to move them into private modules. ... that's the #6282 ticket.

... shadow definitions of builtin methods ... They don't introduce any changes ...

OK.

worth revisiting BuiltinMethod.autoRegister annotation argument.

Builtins...carry a autoRegister property to determine if a builtin method should be automatically registered with the type.

What's the benefit of registering a builtin automatically with the type, @hubertp?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a while ago but IIRC that was specifically requested either by you or @kustosz, so that we don't have to write all those builtin methods as it is done now in this PR.


## PRIVATE
move_builtin self target options = @Builtin_Method "File.move_builtin"

## PRIVATE

Utility function that returns all descendants of the provided file, including
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
/** Defines a stage of compilation of the module. */
public enum CompilationStage {
INITIAL(0),
AFTER_PARSING(1),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this change?

Copy link
Member Author

@radeusgd radeusgd Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was introducing a new stage: AFTER_TYPE_INFERENCE_PASSES, that was supposed to be between two other existing passes. I thought that multiplying the numbers by 10 allows us to introduce such middle stages in the future in an easier manner - one would not need to modify all values as there will still be 'free' integers between existing stage numbers.

But I can just bring this back to a natural 0, 1, 2... ordering if that's preferred - please let me know.

AFTER_IMPORT_RESOLUTION(2),
AFTER_GLOBAL_TYPES(3),
AFTER_STATIC_PASSES(4),
AFTER_RUNTIME_STUBS(5),
AFTER_CODEGEN(6);
AFTER_PARSING(10),
AFTER_IMPORT_RESOLUTION(20),
AFTER_GLOBAL_TYPES(30),
AFTER_STATIC_PASSES(40),
AFTER_TYPE_INFERENCE_PASSES(45),
AFTER_RUNTIME_STUBS(50),
AFTER_CODEGEN(60);

private final int ordinal;

Expand Down
1 change: 1 addition & 0 deletions engine/runtime-compiler/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@
exports org.enso.compiler.phase;
exports org.enso.compiler.phase.exports;
exports org.enso.compiler.refactoring;
exports org.enso.compiler.common_logic;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No snakecase, please. That's not typical Java convention.

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,21 @@ public static <T> T getMetadataOrNull(IR ir, IRPass pass, Class<T> expectedType)
public static <T> T getMetadata(IR ir, IRPass pass, Class<T> expectedType) {
T metadataOrNull = getMetadataOrNull(ir, pass, expectedType);
if (metadataOrNull == null) {
throw new IllegalStateException("Missing expected " + pass + " metadata for " + ir + ".");
String textRepresentation = ir.toString();
if (textRepresentation.length() > 100) {
textRepresentation = textRepresentation.substring(0, 100) + "...";
}

throw new IllegalStateException(
"Missing expected "
+ pass
+ " metadata for "
+ textRepresentation
+ " ("
+ ir.getClass().getCanonicalName()
+ "), had "
+ ir.passData().toString()
+ ".");
}

return metadataOrNull;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package org.enso.compiler.common_logic;

import org.enso.compiler.MetadataInteropHelpers;
import org.enso.compiler.core.ir.Module;
import org.enso.compiler.core.ir.module.scope.Definition;
import org.enso.compiler.core.ir.module.scope.definition.Method;
import org.enso.compiler.core.ir.module.scope.imports.Polyglot;
import org.enso.compiler.data.BindingsMap;
import org.enso.compiler.pass.resolve.MethodDefinitions$;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.jdk.javaapi.CollectionConverters;

/**
* Gathers the common logic for building the ModuleScope.
*
* <p>This is done in two places:
*
* <ol>
* <li>in the compiler, gathering just the types to build StaticModuleScope,
* <li>in the runtime, building Truffle nodes for the interpreter.
* </ol>
*
* <p>The interpreter does much more than the type-checker, so currently this only gathers the
* general shape of the process to try to ensure that they stay in sync. In future iterations, we
* may try to move more of the logic to this common place.
*/
public abstract class BuildScopeFromModuleAlgorithm<
FunctionType,
TypeScopeReferenceType,
ImportExportScopeType,
ModuleScopeType extends
CommonModuleScopeShape<FunctionType, TypeScopeReferenceType, ImportExportScopeType>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow! One should always beware of what one asks for!

ModuleScopeType extends
CommonModuleScopeShape<FunctionType, TypeScopeReferenceType, ImportExportScopeType

Showing object algebras to a functional programmers may lead to code that I no longer understand...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there is any need for T1 extends CT1<....>.

If you want to perform operation on ModuleScopeType, then add a protected abstract method that works on ModuleScopeType.

Avoid extends in the algorithm generic arguments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, okay I can rewrite it to such a form. It felt to me that it's a bit easier and allows me to separate concerns - the parts providing the ModuleScopeType interface were separated from the main algorithm and could be shared across 2 different 'algorithm' abstract classes.

If I put these methods directly into the algorithm, I'll need to duplicate them for each one. How can I ensure I can still share them? I guess I need to create a separate class ModuleScopeInterface<ModuleScopeType> that will allow me to act on the ModuleScopeType values?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, okay I can rewrite it to such a form.

That's indeed my preference. As an alternative...

need to duplicate them for each one

... you can try to convince me that your design is right. I just feel scared for a signature like:

ModuleScopeType extends
        CommonModuleScopeShape<FunctionType, TypeScopeReferenceType, ImportExportScopeType>

ModuleScopeBuilderType extends
CommonModuleScopeShape.Builder<
FunctionType, TypeScopeReferenceType, ImportExportScopeType, ModuleScopeType>> {
private final Logger logger = LoggerFactory.getLogger(BuildScopeFromModuleAlgorithm.class);

/** The scope builder to which the algorithm will register the entities. */
protected final ModuleScopeBuilderType scopeBuilder;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this field protected?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think child classes were also using it in the implementations of the protected methods. If that ceased to be the case and I forgot to notice, I will make it private. Otherwise, if it's used in child classes, do you think it can stay protected?

Because alternatively, I could make it private and store yet another reference to the scope builder in each child class. But storing the same reference twice in the same class felt weird for me and I didn't think it was necessary, that's why I opted for protected final. But I'm open to a different approach if you think it's preferred.


protected BuildScopeFromModuleAlgorithm(ModuleScopeBuilderType scopeBuilder) {
this.scopeBuilder = scopeBuilder;
}

/** Runs the main processing on a module, that will build the module scope for it. */
public void processModule(Module moduleIr, BindingsMap bindingsMap) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall this method be overriden? If not, make it final.

processModuleExports(bindingsMap);
processModuleImports(bindingsMap);
processPolyglotImports(moduleIr);

processBindings(moduleIr);
}

private void processModuleExports(BindingsMap bindingsMap) {
for (var exportedMod :
CollectionConverters.asJavaCollection(bindingsMap.getDirectlyExportedModules())) {
ImportExportScopeType exportScope = buildExportScope(exportedMod);
scopeBuilder.addExport(exportScope);
}
}

private void processModuleImports(BindingsMap bindingsMap) {
for (var imp : CollectionConverters.asJavaCollection(bindingsMap.resolvedImports())) {
for (var target : CollectionConverters.asJavaCollection(imp.targets())) {
if (target instanceof BindingsMap.ResolvedModule resolvedModule) {
var importScope = buildImportScope(imp, resolvedModule);
scopeBuilder.addImport(importScope);
}
}
}
}

private void processPolyglotImports(Module moduleIr) {
for (var imp : CollectionConverters.asJavaCollection(moduleIr.imports())) {
if (imp instanceof Polyglot polyglotImport) {
if (polyglotImport.entity() instanceof Polyglot.Java javaEntity) {
processPolyglotJavaImport(polyglotImport.getVisibleName(), javaEntity.getJavaName());
} else {
throw new IllegalStateException(
"Unsupported polyglot import entity: " + polyglotImport.entity());
}
}
}
}

private void processBindings(Module module) {
for (var binding : CollectionConverters.asJavaCollection(module.bindings())) {
switch (binding) {
case Definition.Type typ -> processTypeDefinition(typ);
case Method.Explicit method -> processMethodDefinition(method);
case Method.Conversion conversion -> processConversion(conversion);
default -> logger.warn(
"Unexpected binding type: {}", binding.getClass().getCanonicalName());
}
}
}

/** Allows the implementation to specify how to register polyglot Java imports. */
protected abstract void processPolyglotJavaImport(String visibleName, String javaClassName);

/**
* Allows the implementation to specify how to register conversions.
*
* <p>In the future we may want to extract some common logic from this, but for now we allow the
* implementation to specify this.
*/
protected abstract void processConversion(Method.Conversion conversion);

/** Allows the implementation to specify how to register method definitions. */
protected abstract void processMethodDefinition(Method.Explicit method);

/**
* Allows the implementation to specify how to register type definitions, along with their
* constructors and getters.
*
* <p>The type registration (registering constructors, getters) is really complex, ideally we'd
* also like to extract some common logic from it. But the differences are very large, so setting
* that aside for later.
*/
protected abstract void processTypeDefinition(Definition.Type typ);

/**
* Common method that allows to extract the type on which the method is defined.
*
* <ul>
* <li>For a member method, this will be its parent type.
* <li>For a static method, this will be the eigentype of the type on which it is defined.
* <li>For a module method, this will be the type associated with the module.
* </ul>
*/
protected final TypeScopeReferenceType getTypeAssociatedWithMethod(Method.Explicit method) {
var typePointerOpt = method.methodReference().typePointer();
if (typePointerOpt.isEmpty()) {
return scopeBuilder.getAssociatedType();
} else {
var metadata =
MetadataInteropHelpers.getMetadataOrNull(
typePointerOpt.get(), MethodDefinitions$.MODULE$, BindingsMap.Resolution.class);
if (metadata == null) {
logger.debug(
"Failed to resolve type pointer for method: {}", method.methodReference().showCode());
return null;
}

return switch (metadata.target()) {
case BindingsMap.ResolvedType resolvedType -> associatedTypeFromResolvedType(
resolvedType, method.isStatic());
case BindingsMap.ResolvedModule resolvedModule -> associatedTypeFromResolvedModule(
resolvedModule);
default -> throw new IllegalStateException(
"Unexpected target type: " + metadata.target().getClass().getCanonicalName());
};
}
}

/**
* Implementation specific piece of {@link #getTypeAssociatedWithMethod(Method.Explicit)} that
* specifies how to build the associated type from a resolved module.
*/
protected abstract TypeScopeReferenceType associatedTypeFromResolvedModule(
BindingsMap.ResolvedModule module);

/**
* Implementation specific piece of {@link #getTypeAssociatedWithMethod(Method.Explicit)} that
* specifies how to build the associated type from a resolved type, depending on if the method is
* static or not.
*/
protected abstract TypeScopeReferenceType associatedTypeFromResolvedType(
BindingsMap.ResolvedType type, boolean isStatic);

/**
* Allows the implementation to specify how to build the export scope from an exported module
* instance.
*
* <p>Such scope is then registered with the scope builder using {@link
* ModuleScopeBuilderType#addExport}.
*/
protected abstract ImportExportScopeType buildExportScope(
BindingsMap.ExportedModule exportedModule);

/**
* Allows the implementation to specify how to build the import scope from a resolved import and
* module.
*
* <p>Such scope is then registered with the scope builder using {@link
* ModuleScopeBuilderType#addImport}.
*/
protected abstract ImportExportScopeType buildImportScope(
BindingsMap.ResolvedImport resolvedImport, BindingsMap.ResolvedModule resolvedModule);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.enso.compiler.common_logic;

import java.util.Collection;

/**
* A common type for module scopes.
*
* <p>It encapsulates the common parts of the module scope that is shared between:
*
* <ul>
* <li>the ModuleScope in the runtime
* <li>the StaticModuleScope in the type checker
* </ul>
*
* @param <FunctionType> the type to which methods are resolved - in the interpreter this will be a
* callable Function reference, in the type-checker this will be a type signature
* @param <TypeScopeReferenceType> the type of type-scope references - they define an 'identity' of
* a type (atom type, its eigen type or module-associated type)
* @param <ImportExportScopeType> the type of import/export scopes - helper types that tie
* import/export relations between modules
*/
public interface CommonModuleScopeShape<
FunctionType, TypeScopeReferenceType, ImportExportScopeType> {

/**
* Returns a method with a given name, defined as a method of the provided type, defined in the
* current scope, or {@code null} if not found.
*/
FunctionType getMethodForType(TypeScopeReferenceType type, String methodName);

/** Returns the collection containing all imports present in the current module. */
Collection<ImportExportScopeType> getImports();

/** Returns the collection containing all exports present in the current module. */
Collection<ImportExportScopeType> getExports();

FunctionType getConversionFor(TypeScopeReferenceType target, TypeScopeReferenceType source);

interface Builder<
FunctionType,
TypeScopeReferenceType,
ImportExportScopeType,
ModuleScopeType extends
CommonModuleScopeShape<FunctionType, TypeScopeReferenceType, ImportExportScopeType>> {

/**
* Builds the module scope and seals it, making it immutable.
*
* <p>The builder should not be used anymore after this method has been called.
*/
ModuleScopeType build();

/** Returns the type (type-scope) associated with the current module. */
TypeScopeReferenceType getAssociatedType();

/** Registers an export in the module scope. */
void addExport(ImportExportScopeType exportScope);

/** Registers an import in the module scope. */
void addImport(ImportExportScopeType importScope);
}
}
Loading
Loading