Make the BindingsMap able to break links (#1980)

This commit is contained in:
Ara Adkins 2021-08-31 15:50:33 +01:00 committed by GitHub
parent 45c01da490
commit 7cced6a9de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 509 additions and 102 deletions

View File

@ -124,7 +124,7 @@ object LauncherApplication {
"(error | warning | info | debug | trace)",
"Sets logging verbosity for the engine. Defaults to info."
)
.withDefault(LogLevel.Info)
.withDefault(LogLevel.Warning)
}
private def runCommand: Command[Config => Int] =

View File

@ -649,7 +649,7 @@ object Main {
/** Default log level to use if the LOG_LEVEL option is not provided.
*/
val defaultLogLevel: LogLevel = LogLevel.Info
val defaultLogLevel: LogLevel = LogLevel.Warning
/** Main entry point for the CLI program.
*

View File

@ -35,10 +35,21 @@ trait PackageRepository {
): Either[PackageRepository.Error, Unit]
/** Get a sequence of currently loaded packages. */
def getLoadedPackages(): Seq[Package[TruffleFile]]
def getLoadedPackages: Seq[Package[TruffleFile]]
/** Get a sequence of currently loaded modules. */
def getLoadedModules(): Seq[Module]
def getLoadedModules: Seq[Module]
/** Get the mapping from qualified module names (equivalent to
* [[QualifiedName.toString]]) to modules.
*
* This map may be updated concurrently.
*/
def getModuleMap: PackageRepository.ModuleMap
/** Gets a frozen form of the module map that cannot be updated concurrently.
*/
def freezeModuleMap: PackageRepository.FrozenModuleMap
/** Get a loaded module by its qualified name. */
def getLoadedModule(qualifiedName: String): Option[Module]
@ -63,6 +74,9 @@ trait PackageRepository {
object PackageRepository {
type ModuleMap = collection.concurrent.Map[String, Module]
type FrozenModuleMap = Map[String, Module]
/** A trait representing errors reported by this system */
sealed trait Error
@ -130,10 +144,23 @@ object PackageRepository {
collection.concurrent.TrieMap(builtinsName -> None)
}
/** The mapping containing loaded modules. */
/** The mapping containing loaded modules.
*
* We use [[String]] as the key as we often index into this map based on
* qualified names that come from interop (via
* [[org.enso.interpreter.runtime.scope.TopLevelScope]]). These arrive as
* Strings, and constantly converting them into [[QualifiedName]]s would
* add more overhead than is probably necessary.
*/
val loadedModules: collection.concurrent.Map[String, Module] =
collection.concurrent.TrieMap(Builtins.MODULE_NAME -> builtins.getModule)
/** @inheritdoc */
override def getModuleMap: ModuleMap = loadedModules
/** @inheritdoc */
override def freezeModuleMap: FrozenModuleMap = loadedModules.toMap
/** @inheritdoc */
override def registerMainProjectPackage(
libraryName: LibraryName,
@ -235,11 +262,11 @@ object PackageRepository {
}
/** @inheritdoc */
override def getLoadedModules(): Seq[Module] =
override def getLoadedModules: Seq[Module] =
loadedModules.values.toSeq
/** @inheritdoc */
override def getLoadedPackages(): Seq[Package[TruffleFile]] =
override def getLoadedPackages: Seq[Package[TruffleFile]] =
loadedPackages.values.toSeq.flatten
/** @inheritdoc */
@ -352,7 +379,7 @@ object PackageRepository {
languageHome = homeManager,
edition = edition,
preferLocalLibraries =
projectPackage.map(_.config.preferLocalLibraries).getOrElse(false)
projectPackage.exists(_.config.preferLocalLibraries)
)
new Default(
resolvingLibraryProvider,

View File

@ -150,7 +150,9 @@ class IrToTruffle(
"No binding analysis at the point of codegen."
)
.resolvedExports
.foreach { exp => moduleScope.addExport(exp.module.getScope) }
.foreach { exp =>
moduleScope.addExport(exp.module.unsafeAsModule().getScope)
}
val imports = module.imports
val atomDefs = module.bindings.collect {
case atom: IR.Module.Scope.Definition.Atom => atom
@ -230,9 +232,13 @@ class IrToTruffle(
.map { res =>
res.target match {
case BindingsMap.ResolvedModule(module) =>
module.getScope.getAssociatedType
module.unsafeAsModule().getScope.getAssociatedType
case BindingsMap.ResolvedConstructor(definitionModule, cons) =>
definitionModule.getScope.getConstructors.get(cons.name)
definitionModule
.unsafeAsModule()
.getScope
.getConstructors
.get(cons.name)
case BindingsMap.ResolvedPolyglotSymbol(_, _) =>
throw new CompilerError(
"Impossible polyglot symbol, should be caught by MethodDefinitions pass."
@ -379,11 +385,14 @@ class IrToTruffle(
)
bindingsMap.exportedSymbols.foreach {
case (name, List(resolution)) =>
if (resolution.module != moduleScope.getModule) {
if (resolution.module.unsafeAsModule() != moduleScope.getModule) {
resolution match {
case BindingsMap.ResolvedConstructor(definitionModule, cons) =>
val runtimeCons =
definitionModule.getScope.getConstructors.get(cons.name)
val runtimeCons = definitionModule
.unsafeAsModule()
.getScope
.getConstructors
.get(cons.name)
val fun = mkConsGetter(runtimeCons)
moduleScope.registerMethod(
moduleScope.getAssociatedType,
@ -392,7 +401,7 @@ class IrToTruffle(
)
case BindingsMap.ResolvedModule(module) =>
val runtimeCons =
module.getScope.getAssociatedType
module.unsafeAsModule().getScope.getAssociatedType
val fun = mkConsGetter(runtimeCons)
moduleScope.registerMethod(
moduleScope.getAssociatedType,
@ -400,8 +409,9 @@ class IrToTruffle(
fun
)
case BindingsMap.ResolvedMethod(module, method) =>
val fun = module.getScope.getMethods
.get(module.getScope.getAssociatedType)
val actualModule = module.unsafeAsModule()
val fun = actualModule.getScope.getMethods
.get(actualModule.getScope.getAssociatedType)
.get(method.name)
moduleScope.registerMethod(
moduleScope.getAssociatedType,
@ -667,13 +677,15 @@ class IrToTruffle(
case Some(
BindingsMap.Resolution(BindingsMap.ResolvedModule(mod))
) =>
Right(mod.getScope.getAssociatedType)
Right(mod.unsafeAsModule().getScope.getAssociatedType)
case Some(
BindingsMap.Resolution(
BindingsMap.ResolvedConstructor(mod, cons)
)
) =>
Right(mod.getScope.getConstructors.get(cons.name))
Right(
mod.unsafeAsModule().getScope.getConstructors.get(cons.name)
)
case Some(
BindingsMap.Resolution(
BindingsMap.ResolvedPolyglotSymbol(_, _)
@ -867,13 +879,23 @@ class IrToTruffle(
resolution match {
case BindingsMap.ResolvedConstructor(definitionModule, cons) =>
ConstructorNode.build(
definitionModule.getScope.getConstructors.get(cons.name)
definitionModule
.unsafeAsModule()
.getScope
.getConstructors
.get(cons.name)
)
case BindingsMap.ResolvedModule(module) =>
ConstructorNode.build(module.getScope.getAssociatedType)
ConstructorNode.build(
module.unsafeAsModule().getScope.getAssociatedType
)
case BindingsMap.ResolvedPolyglotSymbol(module, symbol) =>
ConstantObjectNode.build(
module.getScope.getPolyglotSymbols.get(symbol.name)
module
.unsafeAsModule()
.getScope
.getPolyglotSymbols
.get(symbol.name)
)
case BindingsMap.ResolvedMethod(_, _) =>
throw new CompilerError(

View File

@ -1,9 +1,14 @@
package org.enso.compiler.data
import org.enso.compiler.PackageRepository
import org.enso.compiler.PackageRepository.ModuleMap
import org.enso.compiler.core.IR
import org.enso.compiler.data.BindingsMap.ModuleReference
import org.enso.compiler.exception.CompilerError
import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.BindingAnalysis
import org.enso.interpreter.runtime.Module
import org.enso.pkg.QualifiedName
/** A utility structure for resolving symbols in a given module.
*
@ -16,7 +21,7 @@ case class BindingsMap(
types: List[BindingsMap.Cons],
polyglotSymbols: List[BindingsMap.PolyglotSymbol],
moduleMethods: List[BindingsMap.ModuleMethod],
currentModule: Module
currentModule: ModuleReference
) extends IRPass.Metadata {
import BindingsMap._
@ -28,10 +33,81 @@ case class BindingsMap(
*/
var resolvedImports: List[ResolvedImport] = List()
/** Modules exported by [[currentModule]].
*/
var resolvedExports: List[ExportedModule] = List()
/** Symbols exported by [[currentModule]].
*/
var exportedSymbols: Map[String, List[ResolvedName]] = Map()
/** Convert this [[BindingsMap]] instance to use abstract module references.
*
* @return `this` with module references converted to abstract
*/
def toAbstract: BindingsMap = {
val copy = this.copy(currentModule = currentModule.toAbstract)
copy.resolvedImports = this.resolvedImports.map(_.toAbstract)
copy.resolvedExports = this.resolvedExports.map(_.toAbstract)
copy.exportedSymbols = this.exportedSymbols.map { case (key, value) =>
key -> value.map(name => name.toAbstract)
}
copy
}
/** Convert this [[BindingsMap]] instance to use concrete module references.
*
* @param moduleMap the mapping from qualified module names to module
* instances
* @return `this` with module references converted to concrete
*/
def toConcrete(moduleMap: ModuleMap): Option[BindingsMap] = {
val newMap = this.currentModule.toConcrete(moduleMap).map { module =>
this.copy(currentModule = module)
}
val withImports: Option[BindingsMap] = newMap.flatMap { bindings =>
val newImports = this.resolvedImports.map(_.toConcrete(moduleMap))
if (newImports.exists(_.isEmpty)) {
None
} else {
bindings.resolvedImports = newImports.map(_.get)
Some(bindings)
}
}
val withExports: Option[BindingsMap] = withImports.flatMap { bindings =>
val newExports = this.resolvedExports.map(_.toConcrete(moduleMap))
if (newExports.exists(_.isEmpty)) {
None
} else {
bindings.resolvedExports = newExports.map(_.get)
Some(bindings)
}
}
val withSymbols: Option[BindingsMap] = withExports.flatMap { bindings =>
val newSymbols = this.exportedSymbols.map { case (key, value) =>
val newValue = value.map(_.toConcrete(moduleMap))
if (newValue.exists(_.isEmpty)) {
key -> None
} else {
key -> Some(newValue.map(_.get))
}
}
if (newSymbols.exists { case (_, v) => v.isEmpty }) {
None
} else {
bindings.exportedSymbols = newSymbols.map { case (k, v) => k -> v.get }
Some(bindings)
}
}
withSymbols
}
private def findConstructorCandidates(
name: String
): List[ResolvedConstructor] = {
@ -79,12 +155,19 @@ case class BindingsMap(
resolvedImports
.flatMap { imp =>
if (imp.importDef.allowsAccess(name)) {
imp.module.getIr
.unsafeGetMetadata(
BindingAnalysis,
"Wrong pass ordering. Running resolution on an unparsed module."
)
.findExportedSymbolsFor(name)
imp.module match {
case ModuleReference.Concrete(module) =>
module.getIr
.unsafeGetMetadata(
BindingAnalysis,
"Wrong pass ordering. Running resolution on an unparsed module."
)
.findExportedSymbolsFor(name)
case ModuleReference.Abstract(name) =>
throw new CompilerError(
s"Cannot find export candidates for abstract module reference $name."
)
}
} else { List() }
}
}
@ -99,17 +182,24 @@ case class BindingsMap(
}
}
private def getBindingsFrom(module: Module): BindingsMap = {
module.getIr.unsafeGetMetadata(
BindingAnalysis,
"imported module has no binding map info"
)
private def getBindingsFrom(module: ModuleReference): BindingsMap = {
module match {
case ModuleReference.Concrete(module) =>
module.getIr.unsafeGetMetadata(
BindingAnalysis,
"imported module has no binding map info"
)
case ModuleReference.Abstract(_) =>
throw new CompilerError(
"Bindings cannot be obtained from an abstract module reference."
)
}
}
/** Resolves a name in the context of current module.
*
* @param name the name to resolve.
* @return a resolution for [[name]] or an error, if the name could not be
* @return a resolution for `name` or an error, if the name could not be
* resolved.
*/
def resolveUppercaseName(
@ -430,10 +520,28 @@ object BindingsMap {
* @param symbols any symbol restrictions connected to the export.
*/
case class ExportedModule(
module: Module,
module: ModuleReference,
exportedAs: Option[String],
symbols: SymbolRestriction
)
) {
/** Convert the internal [[ModuleReference]] to an abstract reference.
*
* @return `this` with its module reference made abstract
*/
def toAbstract: ExportedModule = {
this.copy(module = module.toAbstract)
}
/** Convert the internal [[ModuleReference]] to a concrete reference.
*
* @param moduleMap the mapping from qualified names to modules
* @return `this` with its module reference made concrete
*/
def toConcrete(moduleMap: ModuleMap): Option[ExportedModule] = {
module.toConcrete(moduleMap).map(x => this.copy(module = x))
}
}
/** A representation of a resolved import statement.
*
@ -444,8 +552,26 @@ object BindingsMap {
case class ResolvedImport(
importDef: IR.Module.Scope.Import.Module,
exports: Option[IR.Module.Scope.Export.Module],
module: Module
)
module: ModuleReference
) {
/** Convert the internal [[ModuleReference]] to an abstract reference.
*
* @return `this` with its module reference made abstract
*/
def toAbstract: ResolvedImport = {
this.copy(module = module.toAbstract)
}
/** Convert the internal [[ModuleReference]] to a concrete reference.
*
* @param moduleMap the mapping from qualified names to modules
* @return `this` with its module reference made concrete
*/
def toConcrete(moduleMap: ModuleMap): Option[ResolvedImport] = {
module.toConcrete(moduleMap).map(x => this.copy(module = x))
}
}
/** A representation of a constructor.
*
@ -469,7 +595,20 @@ object BindingsMap {
/** A result of successful name resolution.
*/
sealed trait ResolvedName {
def module: Module
def module: ModuleReference
/** Convert the resolved name to abstract form.
*
* @return `this`, converted to abstract form
*/
def toAbstract: ResolvedName
/** Convert the resolved name to concrete form.
*
* @param moduleMap the mapping from qualified names to modules
* @return `this`, converted to concrete form
*/
def toConcrete(moduleMap: ModuleMap): Option[ResolvedName]
}
/** A representation of a name being resolved to a constructor.
@ -477,28 +616,83 @@ object BindingsMap {
* @param module the module the constructor is defined in.
* @param cons a representation of the constructor.
*/
case class ResolvedConstructor(module: Module, cons: Cons)
extends ResolvedName
case class ResolvedConstructor(module: ModuleReference, cons: Cons)
extends ResolvedName {
/** @inheritdoc */
override def toAbstract: ResolvedConstructor = {
this.copy(module = module.toAbstract)
}
/** @inheritdoc */
override def toConcrete(
moduleMap: ModuleMap
): Option[ResolvedConstructor] = {
module.toConcrete(moduleMap).map(module => this.copy(module = module))
}
}
/** A representation of a name being resolved to a module.
*
* @param module the module the name resolved to.
*/
case class ResolvedModule(module: Module) extends ResolvedName
case class ResolvedModule(module: ModuleReference) extends ResolvedName {
/** @inheritdoc */
override def toAbstract: ResolvedModule = {
this.copy(module = module.toAbstract)
}
/** @inheritdoc */
override def toConcrete(
moduleMap: ModuleMap
): Option[ResolvedModule] = {
module.toConcrete(moduleMap).map(module => this.copy(module = module))
}
}
/** A representation of a name being resolved to a method call.
*
* @param module the module defining the method.
* @param method the method representation.
*/
case class ResolvedMethod(module: Module, method: ModuleMethod)
extends ResolvedName
case class ResolvedMethod(module: ModuleReference, method: ModuleMethod)
extends ResolvedName {
/** @inheritdoc */
override def toAbstract: ResolvedMethod = {
this.copy(module = module.toAbstract)
}
/** @inheritdoc */
override def toConcrete(
moduleMap: ModuleMap
): Option[ResolvedMethod] = {
module.toConcrete(moduleMap).map(module => this.copy(module = module))
}
}
/** A representation of a name being resolved to a polyglot symbol.
*
* @param symbol the imported symbol name.
*/
case class ResolvedPolyglotSymbol(module: Module, symbol: PolyglotSymbol)
extends ResolvedName
case class ResolvedPolyglotSymbol(
module: ModuleReference,
symbol: PolyglotSymbol
) extends ResolvedName {
/** @inheritdoc */
override def toAbstract: ResolvedPolyglotSymbol = {
this.copy(module = module.toAbstract)
}
/** @inheritdoc */
override def toConcrete(
moduleMap: ModuleMap
): Option[ResolvedPolyglotSymbol] = {
module.toConcrete(moduleMap).map(module => this.copy(module = module))
}
}
/** A representation of an error during name resolution.
*/
@ -532,4 +726,94 @@ object BindingsMap {
*/
override def duplicate(): Option[IRPass.Metadata] = Some(this)
}
/** A reference to a module.
*/
sealed trait ModuleReference {
/** @return the qualified name of the module
*/
def getName: QualifiedName
/** Convert `this` into a concrete module reference.
*
* @param moduleMap the mapping from qualified names to concrete modules
* @return the concrete module for this reference, if possible
*/
def toConcrete(
moduleMap: PackageRepository.ModuleMap
): Option[ModuleReference.Concrete]
/** Convert `this` into an abstract module reference.
*
* @return the abstract reference to the module represented by `this`
*/
def toAbstract: ModuleReference.Abstract
/** Unsafely coerces the module reference to a concrete one.
*
* @param message the message for if the coercion fails
* @return the concrete version of this reference
*/
@throws[CompilerError]
def unsafeAsModule(message: String = ""): Module
}
object ModuleReference {
/** A module reference that points to a concrete [[Module]] object.
*
* @param module the module being referenced
*/
case class Concrete(module: Module) extends ModuleReference {
/** @inheritdoc */
override def getName: QualifiedName = module.getName
/** Converts `this` into a concrete module reference (a no-op).
*
* @param moduleMap the mapping from qualified names to concrete modules
* @return the concrete module for this reference, if possible
*/
override def toConcrete(moduleMap: ModuleMap): Option[Concrete] =
Some(this)
/** @inheritdoc */
override def toAbstract: Abstract =
ModuleReference.Abstract(module.getName)
/** @inheritdoc */
override def unsafeAsModule(message: String = ""): Module = module
}
/** A module reference that refers to a module by qualified name, without an
* explicit link to the target.
*
* @param name the qualified name (including namespace) of the module
* being referenced
*/
case class Abstract(name: QualifiedName) extends ModuleReference {
/** @inheritdoc */
override def getName: QualifiedName = name
/** @inheritdoc */
override def toConcrete(moduleMap: ModuleMap): Option[Concrete] = {
moduleMap.get(name.toString).map(Concrete)
}
/** Convert `this` into an abstract module reference (a no-op).
*
* @return the abstract reference to the module represented by `this`
*/
override def toAbstract: Abstract = this
/** @inheritdoc */
override def unsafeAsModule(message: String = ""): Module = {
val rest = if (message.isEmpty) "." else s": $message"
val errMsg = s"Could not get concrete module from abstract module $name$rest"
throw new CompilerError(errMsg)
}
}
}
}

View File

@ -4,6 +4,7 @@ import org.enso.compiler.context.{InlineContext, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.core.ir.MetadataStorage.ToPair
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.ModuleReference
import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.desugar.{
ComplexType,
@ -81,7 +82,7 @@ case object BindingAnalysis extends IRPass {
definedConstructors,
importedPolyglot,
methodsWithAutogen,
moduleContext.module
ModuleReference.Concrete(moduleContext.module)
)
)
}

View File

@ -3,7 +3,7 @@ package org.enso.compiler.pass.resolve
import org.enso.compiler.context.{InlineContext, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.ResolvedModule
import org.enso.compiler.data.BindingsMap.{ModuleReference, ResolvedModule}
import org.enso.compiler.exception.CompilerError
import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.AliasAnalysis
@ -46,8 +46,9 @@ case object ModuleThisToHere extends IRPass {
ir: IR.Module,
moduleContext: ModuleContext
): IR.Module = {
val localResolution =
BindingsMap.Resolution(ResolvedModule(moduleContext.module))
val localResolution = BindingsMap.Resolution(
ResolvedModule(ModuleReference.Concrete(moduleContext.module))
)
val newBindings = ir.bindings.map {
case m: IR.Module.Scope.Definition.Method =>
if (

View File

@ -251,7 +251,9 @@ case object UppercaseNames extends IRPass {
): Option[BindingsMap.ResolvedConstructor] =
thisResolution.target match {
case BindingsMap.ResolvedModule(module) =>
val resolution = module.getIr
val resolution = module
.unsafeAsModule()
.getIr
.unsafeGetMetadata(
BindingAnalysis,
"Imported module without bindings analysis results"

View File

@ -4,8 +4,10 @@ import org.enso.compiler.context.{InlineContext, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.core.ir.MetadataStorage.ToPair
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.ModuleReference
import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.BindingAnalysis
import org.enso.interpreter.runtime.Module
case object VectorLiterals extends IRPass {
@ -21,6 +23,9 @@ case object VectorLiterals extends IRPass {
/** The passes that are invalidated by running this pass. */
override val invalidatedPasses: Seq[IRPass] = Seq()
/** The name of the module that contains the Enso stdlib vector definition. */
val vectorModuleName: String = "Standard.Base.Data.Vector"
/** Executes the pass on the provided `ir`, and returns a possibly transformed
* or annotated version of `ir`.
*
@ -64,17 +69,17 @@ case object VectorLiterals extends IRPass {
}
private def vectorCons(bindings: BindingsMap): IR.Expression = {
val module = bindings.resolvedImports
.flatMap(imp =>
imp.module :: imp.module.getIr
.unsafeGetMetadata(
BindingAnalysis,
"no binding analyis on an imported module"
)
.resolvedExports
.map(_.module)
)
.find(_.getName.toString == "Standard.Base.Data.Vector")
val modules: List[Module] = bindings.resolvedImports.flatMap { imp =>
val module = imp.module.unsafeAsModule()
module :: module.getIr
.unsafeGetMetadata(
BindingAnalysis,
"no binding analysis on an imported module"
)
.resolvedExports
.map { export => export.module.unsafeAsModule() }
}
val module = modules.find(_.getName.toString == vectorModuleName)
val name = IR.Name.Literal(
"<Sequence Macro>",
isReferent = true,
@ -86,7 +91,10 @@ case object VectorLiterals extends IRPass {
val withRes = name.updateMetadata(
UppercaseNames -->> BindingsMap.Resolution(
BindingsMap
.ResolvedConstructor(module, BindingsMap.Cons("Vector", 1))
.ResolvedConstructor(
ModuleReference.Concrete(module),
BindingsMap.Cons("Vector", 1)
)
)
)
withRes

View File

@ -3,6 +3,7 @@ package org.enso.compiler.phase
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.{
ExportedModule,
ModuleReference,
ResolvedConstructor,
ResolvedMethod,
ResolvedModule,
@ -53,7 +54,7 @@ class ExportsResolution {
val node = nodes(module)
node.exports = exports.map {
case ExportedModule(mod, rename, restriction) =>
Edge(node, restriction, rename, nodes(mod))
Edge(node, restriction, rename, nodes(mod.unsafeAsModule()))
}
node.exports.foreach { edge => edge.exportee.exportedBy ::= edge }
}
@ -122,12 +123,16 @@ class ExportsResolution {
nodes.foreach { node =>
val explicitlyExported =
node.exports.map(edge =>
ExportedModule(edge.exportee.module, edge.exportsAs, edge.symbols)
ExportedModule(
ModuleReference.Concrete(edge.exportee.module),
edge.exportsAs,
edge.symbols
)
)
val transitivelyExported: List[ExportedModule] =
explicitlyExported.flatMap {
case ExportedModule(module, _, restriction) =>
exports(module).map {
exports(module.unsafeAsModule()).map {
case ExportedModule(export, _, parentRestriction) =>
ExportedModule(
export,
@ -160,27 +165,36 @@ class ExportsResolution {
private def resolveExportedSymbols(modules: List[Module]): Unit = {
modules.foreach { module =>
val bindings = getBindings(module)
val ownMethods = bindings.moduleMethods.map(method =>
(method.name.toLowerCase, List(ResolvedMethod(module, method)))
)
val ownConstructors = bindings.types.map(tp =>
(tp.name.toLowerCase, List(ResolvedConstructor(module, tp)))
)
val ownPolyglotBindings = bindings.polyglotSymbols.map(poly =>
(poly.name.toLowerCase, List(ResolvedPolyglotSymbol(module, poly)))
)
val ownMethods = bindings.moduleMethods.map { method =>
val name = method.name.toLowerCase
val syms =
List(ResolvedMethod(ModuleReference.Concrete(module), method))
(name, syms)
}
val ownConstructors = bindings.types.map { tp =>
val name = tp.name.toLowerCase
val types =
List(ResolvedConstructor(ModuleReference.Concrete(module), tp))
(name, types)
}
val ownPolyglotBindings = bindings.polyglotSymbols.map { poly =>
val name = poly.name.toLowerCase
val syms =
List(ResolvedPolyglotSymbol(ModuleReference.Concrete(module), poly))
(name, syms)
}
val exportedModules = bindings.resolvedExports.collect {
case ExportedModule(mod, Some(name), _) =>
(name.toLowerCase, List(ResolvedModule(mod)))
}
val reExportedSymbols = bindings.resolvedExports.flatMap { export =>
getBindings(export.module).exportedSymbols.toList.flatMap {
case (sym, resolutions) =>
getBindings(export.module.unsafeAsModule()).exportedSymbols.toList
.flatMap { case (sym, resolutions) =>
val allowedResolutions =
resolutions.filter(res => export.symbols.canAccess(sym, res))
if (allowedResolutions.isEmpty) None
else Some((sym, allowedResolutions))
}
}
}
bindings.exportedSymbols = List(
ownMethods,

View File

@ -3,6 +3,7 @@ package org.enso.compiler.phase
import org.enso.compiler.Compiler
import org.enso.compiler.core.IR
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.ModuleReference
import org.enso.compiler.exception.CompilerError
import org.enso.compiler.pass.analyse.BindingAnalysis
import org.enso.editions.LibraryName
@ -78,7 +79,13 @@ class ImportResolver(compiler: Compiler) {
case Some(module) =>
(
imp,
Some(BindingsMap.ResolvedImport(imp, exp, module))
Some(
BindingsMap.ResolvedImport(
imp,
exp,
ModuleReference.Concrete(module)
)
)
)
case None =>
(
@ -112,7 +119,9 @@ class ImportResolver(compiler: Compiler) {
}
// continue with updated stack
go(
stack.pushAll(currentLocal.resolvedImports.map(_.module)),
stack.pushAll(
currentLocal.resolvedImports.map(_.module.unsafeAsModule())
),
seen += current
)
}

View File

@ -3,7 +3,11 @@ package org.enso.compiler.phase
import org.enso.compiler.core.IR
import org.enso.compiler.core.ir.MetadataStorage._
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.{ResolvedConstructor, ResolvedMethod}
import org.enso.compiler.data.BindingsMap.{
ModuleReference,
ResolvedConstructor,
ResolvedMethod
}
import org.enso.compiler.pass.analyse.BindingAnalysis
import org.enso.interpreter.runtime.Module
@ -39,13 +43,18 @@ object StubIrBuilder {
val polyglot = scope.getPolyglotSymbols.asScala.keys.toList
.map(BindingsMap.PolyglotSymbol)
val exportedBindings = definedConstructors.map(c =>
(c.name.toLowerCase, List(ResolvedConstructor(module, c)))
) ++ moduleMethods.map(m => (m.name, List(ResolvedMethod(module, m))))
(
c.name.toLowerCase,
List(ResolvedConstructor(ModuleReference.Concrete(module), c))
)
) ++ moduleMethods.map(m =>
(m.name, List(ResolvedMethod(ModuleReference.Concrete(module), m)))
)
val meta = BindingsMap(
definedConstructors,
polyglot,
moduleMethods,
module
ModuleReference.Concrete(module)
)
meta.exportedSymbols = exportedBindings.toMap
ir.updateMetadata(BindingAnalysis -->> meta)

View File

@ -3,7 +3,7 @@ package org.enso.compiler.test.pass.analyse
import org.enso.compiler.Passes
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.data.BindingsMap.{Cons, ModuleMethod, PolyglotSymbol}
import org.enso.compiler.data.BindingsMap.{Cons, ModuleMethod, ModuleReference, PolyglotSymbol}
import org.enso.compiler.pass.analyse.BindingAnalysis
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
import org.enso.compiler.test.CompilerTest
@ -37,7 +37,7 @@ class BindingAnalysisTest extends CompilerTest {
* @param context the module context in which analysis takes place
* @return [[ir]], with tail call analysis metadata attached
*/
def analyse(implicit context: ModuleContext) = {
def analyse(implicit context: ModuleContext): IR.Module = {
BindingAnalysis.runModule(ir, context)
}
}
@ -82,7 +82,7 @@ class BindingAnalysisTest extends CompilerTest {
ModuleMethod("enso_project"),
ModuleMethod("foo")
)
metadata.currentModule shouldEqual ctx.module
metadata.currentModule shouldEqual ModuleReference.Concrete(ctx.module)
}
"properly assign module-level methods when a type with the same name as module is defined" in {

View File

@ -4,7 +4,7 @@ import org.enso.compiler.Passes
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.data.BindingsMap
import org.enso.compiler.data.BindingsMap.Cons
import org.enso.compiler.data.BindingsMap.{Cons, ModuleReference}
import org.enso.compiler.pass.resolve.MethodDefinitions
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
import org.enso.compiler.test.CompilerTest
@ -77,7 +77,7 @@ class MethodDefinitionsTest extends CompilerTest {
.getMetadata(MethodDefinitions) shouldEqual Some(
BindingsMap.Resolution(
BindingsMap.ResolvedConstructor(
ctx.module,
ModuleReference.Concrete(ctx.module),
Cons("Foo", 3)
)
)
@ -88,7 +88,7 @@ class MethodDefinitionsTest extends CompilerTest {
.typePointer
.getMetadata(MethodDefinitions) shouldEqual Some(
BindingsMap.Resolution(
BindingsMap.ResolvedModule(ctx.module)
BindingsMap.ResolvedModule(ModuleReference.Concrete(ctx.module))
)
)
ir.bindings(4)
@ -97,7 +97,7 @@ class MethodDefinitionsTest extends CompilerTest {
.typePointer
.getMetadata(MethodDefinitions) shouldEqual Some(
BindingsMap.Resolution(
BindingsMap.ResolvedModule(ctx.module)
BindingsMap.ResolvedModule(ModuleReference.Concrete(ctx.module))
)
)
ir.bindings(5)
@ -112,12 +112,18 @@ class MethodDefinitionsTest extends CompilerTest {
MethodDefinitions
) shouldEqual Some(
BindingsMap.Resolution(
BindingsMap.ResolvedConstructor(ctx.module, Cons("Foo", 3))
BindingsMap.ResolvedConstructor(
ModuleReference.Concrete(ctx.module),
Cons("Foo", 3)
)
)
)
conv1.sourceTypeName.getMetadata(MethodDefinitions) shouldEqual Some(
BindingsMap.Resolution(
BindingsMap.ResolvedConstructor(ctx.module, Cons("Bar", 0))
BindingsMap.ResolvedConstructor(
ModuleReference.Concrete(ctx.module),
Cons("Bar", 0)
)
)
)
@ -128,7 +134,10 @@ class MethodDefinitionsTest extends CompilerTest {
MethodDefinitions
) shouldEqual Some(
BindingsMap.Resolution(
BindingsMap.ResolvedConstructor(ctx.module, Cons("Bar", 0))
BindingsMap.ResolvedConstructor(
ModuleReference.Concrete(ctx.module),
Cons("Bar", 0)
)
)
)
conv2.sourceTypeName shouldBe an[IR.Error.Resolution]
@ -139,7 +148,10 @@ class MethodDefinitionsTest extends CompilerTest {
conv3.methodReference.typePointer shouldBe an[IR.Error.Resolution]
conv3.sourceTypeName.getMetadata(MethodDefinitions) shouldEqual Some(
BindingsMap.Resolution(
BindingsMap.ResolvedConstructor(ctx.module, Cons("Foo", 3))
BindingsMap.ResolvedConstructor(
ModuleReference.Concrete(ctx.module),
Cons("Foo", 3)
)
)
)
}

View File

@ -5,6 +5,7 @@ import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.data.BindingsMap.{
Cons,
ModuleReference,
Resolution,
ResolvedConstructor
}
@ -85,7 +86,12 @@ class PatternsTest extends CompilerTest {
.asInstanceOf[IR.Pattern.Constructor]
.constructor
.getMetadata(Patterns) shouldEqual Some(
Resolution(ResolvedConstructor(ctx.module, Cons("Foo", 3)))
Resolution(
ResolvedConstructor(
ModuleReference.Concrete(ctx.module),
Cons("Foo", 3)
)
)
)
patterns(1) shouldBe a[IR.Error.Pattern]
patterns(2)

View File

@ -5,6 +5,7 @@ import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.data.BindingsMap.{
Cons,
ModuleReference,
Resolution,
ResolvedConstructor,
ResolvedModule
@ -94,7 +95,12 @@ class UppercaseNamesTest extends CompilerTest {
.asInstanceOf[IR.Application.Prefix]
.function
.getMetadata(UppercaseNames) shouldEqual Some(
Resolution(ResolvedConstructor(ctx.module, Cons("My_Cons", 3)))
Resolution(
ResolvedConstructor(
ModuleReference.Concrete(ctx.module),
Cons("My_Cons", 3)
)
)
)
}
@ -105,7 +111,7 @@ class UppercaseNamesTest extends CompilerTest {
app.function.asInstanceOf[IR.Name.Literal].name shouldEqual "constant"
app.arguments.length shouldEqual 1
app.arguments(0).value.getMetadata(UppercaseNames) shouldEqual Some(
Resolution(ResolvedModule(ctx.module))
Resolution(ResolvedModule(ModuleReference.Concrete(ctx.module)))
)
}
@ -116,7 +122,7 @@ class UppercaseNamesTest extends CompilerTest {
app.function.asInstanceOf[IR.Name.Literal].name shouldEqual "add_one"
app.arguments.length shouldEqual 2
app.arguments(0).value.getMetadata(UppercaseNames) shouldEqual Some(
Resolution(ResolvedModule(ctx.module))
Resolution(ResolvedModule(ModuleReference.Concrete(ctx.module)))
)
}
@ -124,7 +130,12 @@ class UppercaseNamesTest extends CompilerTest {
val app = bodyExprs(3).asInstanceOf[IR.Application.Prefix]
app.arguments.length shouldBe 3
app.function.getMetadata(UppercaseNames) shouldEqual Some(
Resolution(ResolvedConstructor(ctx.module, Cons("My_Cons", 3)))
Resolution(
ResolvedConstructor(
ModuleReference.Concrete(ctx.module),
Cons("My_Cons", 3)
)
)
)
}

View File

@ -1,5 +1,6 @@
package org.enso.interpreter.test.instrument
import org.enso.compiler.pass.resolve.VectorLiterals
import org.enso.distribution.FileSystem
import org.enso.distribution.locking.ThreadSafeFileLockManager
import org.enso.interpreter.test.Metadata
@ -204,7 +205,7 @@ class RuntimeStdlibTest
)
) if module.contains("Vector") =>
(xs.nonEmpty || as.nonEmpty) shouldBe true
xs.toVector.head.suggestion.module shouldEqual "Standard.Base.Data.Vector"
xs.toVector.head.suggestion.module shouldEqual VectorLiterals.vectorModuleName
}
stdlibSuggestions.nonEmpty shouldBe true