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

Import resolution throws exception for non-existing symbols #6457

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d1762c0
[WIP] Add some tests
Akirathan May 2, 2023
ff5856b
Improve docs
Akirathan May 2, 2023
b77252e
bench_download_tool: since and until are dates, not datetimes
Akirathan May 3, 2023
6c06775
[WIP] Add SymbolsImportResolution compiler step
Akirathan May 5, 2023
14b7e1d
Add test for a malformed from import
Akirathan May 5, 2023
2348881
Update tests
Akirathan May 5, 2023
b31dfb0
Add logging
Akirathan May 8, 2023
a46b07d
SymbolsImportResolution can resolve members of types
Akirathan May 8, 2023
74325e2
Add ImportExportsTest
Akirathan May 8, 2023
5833208
Use custom GraalVM context in ImportExportTest
Akirathan May 9, 2023
f9bce18
Merge branch 'develop' into wip/akirathan/import-from-error-5936
Akirathan May 9, 2023
163e537
Add some ImportsExportsTest
Akirathan May 9, 2023
4b94353
Fix SYmbolsImportResolution so that it can:
May 11, 2023
3f1b2bf
ImportResolver can can resolve a type or a static method from a module
May 11, 2023
bc0eebf
Add some error messages to IR's ImportExport error reasons
May 11, 2023
e3c22d6
ResolvedConstructor and ResolvedMethod can also be ImportTarget
May 11, 2023
6f4df8c
Add more import/export tests
May 11, 2023
a283dc8
Add final version of ImportExportTest
Akirathan May 12, 2023
3ef09bd
Do not create modules outside test context
Akirathan May 12, 2023
48db11d
Remove duplicated test
Akirathan May 12, 2023
9ba4f25
Append all the transitive imports to the resolvedImports
Akirathan May 12, 2023
2c5ea96
Fix compilation
Akirathan May 12, 2023
903e73d
Fix findAllStaticMethodsAndTypes.
Akirathan May 12, 2023
cbedc07
Describe ignored tests
Akirathan May 12, 2023
aacbdff
Fix rest of ImportExportTest
Akirathan May 12, 2023
a8b93b9
Add "assign module-level foreign static method" to BindingAnalysisTest
Akirathan May 12, 2023
7a38656
Turn off logging in ImportExportTest
Akirathan May 12, 2023
22c9727
Use `Either` for `SymbolResolution` result type
Akirathan May 12, 2023
961678a
Remove deprecated methods of `Either`
Akirathan May 12, 2023
a4af67b
Use flatMap instead of the mutable buffer
Akirathan May 12, 2023
85c8e5d
Add some default implementation for overriden methods in Resolved nam…
Akirathan May 12, 2023
66e662d
Use flatMap instead of mutable buffer
Akirathan May 12, 2023
d0bac0e
Refactoring - move methods in SymbolsImportResolution
Akirathan May 12, 2023
bd6ae72
scalafmtAll
Akirathan May 12, 2023
16fdebf
Merge branch 'develop' into wip/akirathan/import-from-error-5936
Akirathan May 16, 2023
a65e487
Fix find methods for ResolvedConstructor and ResolvedMethod
Akirathan May 16, 2023
36c0b74
Remove multiple imports of the same symbol
Akirathan May 16, 2023
ff0e1c7
Add some tests for exporting and checks for `findExportedSymbolsFor` …
Akirathan May 17, 2023
ea6185d
ResolvedConstructor and ResolvedMethod do not export any symbols in `…
Akirathan May 17, 2023
6a8ad23
Add more tests
Akirathan May 17, 2023
3cb1428
Cosmetics
Akirathan May 17, 2023
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 @@ -24,7 +24,6 @@ import project.Runtime.Managed_Resource.Managed_Resource
import project.System.File.File_Access.File_Access
import project.System.File.File_Permissions.File_Permissions

from project.Data.Boolean import Boolean, True, False
from project.System.File_Format import Auto_Detect, File_Format, format_widget

import project.Metadata.Widget
Expand Down
29 changes: 26 additions & 3 deletions engine/runtime/src/main/scala/org/enso/compiler/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import org.enso.compiler.pass.analyse._
import org.enso.compiler.phase.{
ExportCycleException,
ExportsResolution,
ImportResolver
ImportResolver,
SymbolsImportResolution
}
import org.enso.editions.LibraryName
import org.enso.interpreter.node.{ExpressionNode => RuntimeExpression}
Expand All @@ -34,7 +35,6 @@ import java.util.concurrent.{
TimeUnit
}
import java.util.logging.Level

import scala.jdk.OptionConverters._
import java.util.concurrent.Future

Expand All @@ -54,6 +54,8 @@ class Compiler(
private val passes: Passes = new Passes(config)
private val passManager: PassManager = passes.passManager
private val importResolver: ImportResolver = new ImportResolver(this)
private val symbolImportsResolver: SymbolsImportResolution =
new SymbolsImportResolution(this)
private val stubsGenerator: RuntimeStubsGenerator =
new RuntimeStubsGenerator(builtins)
private val irCachingEnabled = !context.isIrCachingDisabled
Expand Down Expand Up @@ -189,7 +191,7 @@ class Compiler(
logger.log(
Level.SEVERE,
"Could not find entry point for compilation in package [{0}.{1}]",
Array(pkg.namespace, pkg.name)
Array[Object](pkg.namespace, pkg.name)
)
CompletableFuture.completedFuture(false)
case Some(m) =>
Expand Down Expand Up @@ -434,13 +436,24 @@ class Compiler(
module: Module,
bindingsCachingEnabled: Boolean
): List[Module] = {
logger.log(
Level.FINER,
"Running imports and exports resolution for module {0}",
Array[Object](module.getName.toString)
)
val (importedModules, modulesImportedWithCachedBindings) =
try {
importResolver.mapImports(module, bindingsCachingEnabled)
} catch {
case e: ImportResolver.HiddenNamesConflict => reportExportConflicts(e)
}

logger.log(
Level.FINER,
"Modules to be imported: [{0}]",
Array[Object](importedModules.map(_.getName.toString))
)

val requiredModules =
try { new ExportsResolution().run(importedModules) }
catch { case e: ExportCycleException => reportCycle(e) }
Expand All @@ -457,8 +470,18 @@ class Compiler(
}
}

logger.log(
Level.FINER,
"Required modules after exports resolution: [{0}]",
Array[Object](requiredModules.map(_.getName.toString))
)

joinAllFutures(parsingTasks).get()

// Symbol imports resolution has to be done after the exports resolution
requiredModules.foreach(module =>
symbolImportsResolver.resolveImportSymbols(module)
)
// ** Order matters for codegen **
// Consider a case when an exported symbol is referenced but the module that defines the symbol
// has not yet registered the method in its scope. This will result in No_Such_Method method during runtime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ class IrToTruffle(

bindingsMap.resolvedImports.foreach { imp =>
imp.target match {
case BindingsMap.ResolvedType(_, _) =>
case _: BindingsMap.ResolvedType =>
case _: BindingsMap.ResolvedMethod =>
case _: BindingsMap.ResolvedConstructor =>
case ResolvedModule(module) =>
val mod = module.unsafeAsModule()
val scope: ModuleScope = imp.importDef.onlyNames
Expand Down
24 changes: 23 additions & 1 deletion engine/runtime/src/main/scala/org/enso/compiler/core/IR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import org.enso.interpreter.epb.EpbParser
import org.enso.syntax.text.{Debug, Location}

import java.util.UUID

import scala.annotation.unused

/** [[IR]] is a temporary and fairly unsophisticated internal representation
Expand Down Expand Up @@ -8783,6 +8782,29 @@ object IR {
override def message: String = s"The module $name does not exist."
}

case class TypeDoesNotExist(
typeName: String,
moduleName: String
) extends Reason {
override def message: String =
s"The type $typeName does not exist in module $moduleName"
}

case class SymbolsDoNotExist(
symbolNames: List[String],
moduleName: String
) extends Reason {
override def message: String =
s"The symbols $symbolNames (modules or types) do not exist in module $moduleName."
}

case class NoSuchConstructor(
typeName: String,
constructorName: String
) extends Reason {
override def message: String =
s"No such constructor '$constructorName' in type $typeName"
}
}

/** An erroneous import or export statement.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ import scala.annotation.unused

/** A utility structure for resolving symbols in a given module.
*
* @param constructors the types defined in the current module
* @param polyglotSymbols the polyglot symbols imported into the scope
* @param moduleMethods the methods defined with current module as `this`
* @param currentModule the module holding these bindings
*/

Expand Down Expand Up @@ -256,9 +253,6 @@ case class BindingsMap(

/** Dumps the export statements from this module into a structure ready for
* further analysis.
*
* @return a list of triples of the exported module, the name it is exported
* as and any further symbol restrictions.
*/
def getDirectlyExportedModules: List[ExportedModule] =
resolvedImports.collect { case ResolvedImport(_, exports, mod) =>
Expand Down Expand Up @@ -653,7 +647,15 @@ object BindingsMap {
sealed trait ImportTarget extends ResolvedName {
override def toAbstract: ImportTarget
override def toConcrete(moduleMap: ModuleMap): Option[ImportTarget]
def findExportedSymbolsFor(name: String): List[ResolvedName]

/** Find all exported symbols for a given name.
* More specifically, this method answers the following question: "If all symbols are imported
* from this import target via `from <ImportTarget> import all` statement, is `name` one of
* these symbols?"
* @param name the name to search for
* @return a list of all exported symbols with the given name
*/
def findExportedSymbolsFor(name: String): List[ResolvedName]
def resolveExportedSymbol(
name: String
): Either[ResolutionError, ResolvedName] =
Expand All @@ -665,7 +667,7 @@ object BindingsMap {
*
* @param importDef the definition of the import
* @param exports the exports associated with the import
* @param target the module this import resolves to
* @param target the module or type this import resolves to
*/
case class ResolvedImport(
importDef: IR.Module.Scope.Import.Module,
Expand Down Expand Up @@ -724,7 +726,7 @@ object BindingsMap {
/** A representation of a sum type
*
* @param name the type name
* @param members the member names
* @param members the member names - constructors only.
* @param builtinType true if constructor is annotated with @Builtin_Type, false otherwise.
*/
case class Type(
Expand Down Expand Up @@ -816,7 +818,8 @@ object BindingsMap {
* @param cons a representation of the constructor.
*/
case class ResolvedConstructor(tpe: ResolvedType, cons: Cons)
extends ResolvedName {
extends ResolvedName
with ImportTarget {

/** @inheritdoc */
override def toAbstract: ResolvedConstructor = {
Expand All @@ -836,6 +839,12 @@ object BindingsMap {

/** @inheritdoc */
override def module: ModuleReference = tpe.module

override def findExportedSymbolsFor(name: String): List[ResolvedName] =
List()

override def exportedSymbols: Map[String, List[ResolvedName]] =
Map(cons.name -> List(this))
}

/** A representation of a name being resolved to a module.
Expand Down Expand Up @@ -879,7 +888,8 @@ object BindingsMap {
* @param method the method representation.
*/
case class ResolvedMethod(module: ModuleReference, method: ModuleMethod)
extends ResolvedName {
extends ResolvedName
with ImportTarget {

/** @inheritdoc */
override def toAbstract: ResolvedMethod = {
Expand Down Expand Up @@ -914,6 +924,12 @@ object BindingsMap {

override def qualifiedName: QualifiedName =
module.getName.createChild(method.name)

override def findExportedSymbolsFor(name: String): List[ResolvedName] =
List()

override def exportedSymbols: Map[String, List[ResolvedName]] =
Map(method.name -> List(this))
}

/** A representation of a name being resolved to a polyglot symbol.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.enso.interpreter.runtime.Module
/** Partially resolves fully qualified names corresponding to the library names
*
* 1. Identifies potential library names e.g., `Standard.Base`
* 2. If the component has not be compiled yet, compilation is triggered
* 2. If the component has not been compiled yet, compilation is triggered
* 3. Replaces the library name with a fresh name and a resolved Main module
*/
case object FullyQualifiedNames extends IRPass {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ class ExportsResolution {
}
exports.foreach { case (module, exports) =>
module match {
case _: BindingsMap.ResolvedType =>
case _: BindingsMap.ResolvedType =>
case _: BindingsMap.ResolvedConstructor =>
case _: BindingsMap.ResolvedMethod =>
case ResolvedModule(module) =>
getBindings(module.unsafeAsModule()).resolvedExports =
exports.map(ex => ex.copy(symbols = ex.symbols.optimize))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.Module.Scope.{Export, Import}
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.{
ImportTarget,
ModuleReference,
ResolvedMethod,
ResolvedModule,
ResolvedType,
Type
Expand Down Expand Up @@ -34,7 +36,7 @@ class ImportResolver(compiler: Compiler) {
*
* @param module the entry-point module.
* @return a tuple containing a list of all modules that need to go through the full compilation pipeline and
* a list of all modules which have been inferred from bindings cache and could potentially be compiled lazilly
* a list of all modules which have been inferred from bindings cache and could potentially be compiled lazily
*/
def mapImports(
module: Module,
Expand Down Expand Up @@ -132,22 +134,25 @@ class ImportResolver(compiler: Compiler) {
go(mutable.Stack(module), mutable.Set(), mutable.Set())
}

private def tryResolveAsType(
private def tryResolveAsTypeOrStaticMethod(
name: IR.Name.Qualified
): Option[ResolvedType] = {
val tp = name.parts.last.name
val mod = name.parts.dropRight(1).map(_.name).mkString(".")
compiler.getModule(mod).flatMap { mod =>
): Option[ImportTarget] = {
val nameToImportFromModule = name.parts.last.name
val moduleName = name.parts.dropRight(1).map(_.name).mkString(".")
compiler.getModule(moduleName).flatMap { mod =>
compiler.ensureParsed(mod)
mod.getIr
.unsafeGetMetadata(
BindingAnalysis,
"impossible: just ensured it's parsed"
)
.definedEntities
.find(_.name == tp)
.collect { case t: Type =>
ResolvedType(ModuleReference.Concrete(mod), t)
.find(_.name == nameToImportFromModule)
.collect {
case t: Type =>
ResolvedType(ModuleReference.Concrete(mod), t)
case m: BindingsMap.ModuleMethod =>
ResolvedMethod(ModuleReference.Concrete(mod), m)
}
}
}
Expand Down Expand Up @@ -242,9 +247,9 @@ class ImportResolver(compiler: Compiler) {
)
)
case None =>
tryResolveAsType(imp.name) match {
case Some(tp) =>
(imp, Some(BindingsMap.ResolvedImport(imp, exp, tp)))
tryResolveAsTypeOrStaticMethod(imp.name) match {
case Some(importTarget) =>
(imp, Some(BindingsMap.ResolvedImport(imp, exp, importTarget)))
case None =>
(
IR.Error.ImportExport(
Expand Down
Loading