Un-nest AliasAnalysis Info and Graph to allow easier usage from Java (#9451)

This commit is contained in:
Radosław Waśko 2024-03-18 16:16:24 +01:00 committed by GitHub
parent de9f2764f9
commit 90b3003312
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 1000 additions and 922 deletions

View File

@ -1,7 +1,8 @@
package org.enso.compiler.pass.analyse; package org.enso.compiler.pass.analyse;
import java.io.IOException; import java.io.IOException;
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph; import org.enso.compiler.pass.analyse.alias.Graph;
import org.enso.compiler.pass.analyse.alias.Info;
import org.enso.compiler.pass.resolve.DocumentationComments; import org.enso.compiler.pass.resolve.DocumentationComments;
import org.enso.compiler.pass.resolve.DocumentationComments$; import org.enso.compiler.pass.resolve.DocumentationComments$;
import org.enso.compiler.pass.resolve.ExpressionAnnotations$; import org.enso.compiler.pass.resolve.ExpressionAnnotations$;
@ -54,12 +55,24 @@ import scala.Option;
@Persistable(clazz = GenericAnnotations$.class, id = 1216) @Persistable(clazz = GenericAnnotations$.class, id = 1216)
@Persistable(clazz = ExpressionAnnotations$.class, id = 1217) @Persistable(clazz = ExpressionAnnotations$.class, id = 1217)
@Persistable(clazz = FullyQualifiedNames$.class, id = 1218) @Persistable(clazz = FullyQualifiedNames$.class, id = 1218)
@Persistable(clazz = AliasAnalysis$Info$Occurrence.class, id = 1261, allowInlining = false) @Persistable(clazz = Info.Occurrence.class, id = 1261, allowInlining = false)
@Persistable(clazz = AliasAnalysis$Info$Scope$Root.class, id = 1262, allowInlining = false) @Persistable(
@Persistable(clazz = AliasAnalysis$Info$Scope$Child.class, id = 1263, allowInlining = false) clazz = org.enso.compiler.pass.analyse.alias.Info$Scope$Root.class,
@Persistable(clazz = AliasAnalysis$Graph$Occurrence$Use.class, id = 1264, allowInlining = false) id = 1262,
@Persistable(clazz = AliasAnalysis$Graph$Occurrence$Def.class, id = 1265, allowInlining = false) allowInlining = false)
@Persistable(clazz = AliasAnalysis$Graph$Link.class, id = 1266, allowInlining = false) @Persistable(
clazz = org.enso.compiler.pass.analyse.alias.Info$Scope$Child.class,
id = 1263,
allowInlining = false)
@Persistable(
clazz = org.enso.compiler.pass.analyse.alias.Graph$Occurrence$Use.class,
id = 1264,
allowInlining = false)
@Persistable(
clazz = org.enso.compiler.pass.analyse.alias.Graph$Occurrence$Def.class,
id = 1265,
allowInlining = false)
@Persistable(clazz = Graph.Link.class, id = 1266, allowInlining = false)
public final class PassPersistance { public final class PassPersistance {
private PassPersistance() {} private PassPersistance() {}
@ -106,26 +119,22 @@ public final class PassPersistance {
} }
@org.openide.util.lookup.ServiceProvider(service = Persistance.class) @org.openide.util.lookup.ServiceProvider(service = Persistance.class)
public static final class PersistAliasAnalysisGraphScope public static final class PersistAliasAnalysisGraphScope extends Persistance<Graph.Scope> {
extends Persistance<org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope> {
public PersistAliasAnalysisGraphScope() { public PersistAliasAnalysisGraphScope() {
super(org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope.class, false, 1267); super(Graph.Scope.class, false, 1267);
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope readObject(Input in) protected Graph.Scope readObject(Input in) throws IOException {
throws IOException {
var childScopes = in.readInline(scala.collection.immutable.List.class); var childScopes = in.readInline(scala.collection.immutable.List.class);
var occurrences = (scala.collection.immutable.Set) in.readObject(); var occurrences = (scala.collection.immutable.Set) in.readObject();
var allDefinitions = in.readInline(scala.collection.immutable.List.class); var allDefinitions = in.readInline(scala.collection.immutable.List.class);
var parent = var parent = new Graph.Scope(childScopes, occurrences, allDefinitions);
new org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope(
childScopes, occurrences, allDefinitions);
var optionParent = Option.apply(parent); var optionParent = Option.apply(parent);
childScopes.forall( childScopes.forall(
(object) -> { (object) -> {
var ch = (org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope) object; var ch = (Graph.Scope) object;
ch.parent_$eq(optionParent); ch.parent_$eq(optionParent);
return null; return null;
}); });
@ -134,9 +143,7 @@ public final class PassPersistance {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void writeObject( protected void writeObject(Graph.Scope obj, Output out) throws IOException {
org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope obj, Output out)
throws IOException {
out.writeInline(scala.collection.immutable.List.class, obj.childScopes()); out.writeInline(scala.collection.immutable.List.class, obj.childScopes());
out.writeObject(obj.occurrences()); out.writeObject(obj.occurrences());
out.writeInline(scala.collection.immutable.List.class, obj.allDefinitions()); out.writeInline(scala.collection.immutable.List.class, obj.allDefinitions());
@ -153,7 +160,7 @@ public final class PassPersistance {
protected Graph readObject(Input in) throws IOException { protected Graph readObject(Input in) throws IOException {
var g = new Graph(); var g = new Graph();
var rootScope = (AliasAnalysis$Graph$Scope) in.readObject(); var rootScope = (Graph.Scope) in.readObject();
assignParents(rootScope); assignParents(rootScope);
g.rootScope_$eq(rootScope); g.rootScope_$eq(rootScope);
@ -175,7 +182,7 @@ public final class PassPersistance {
out.writeInt(obj.nextIdCounter()); out.writeInt(obj.nextIdCounter());
} }
private static void assignParents(AliasAnalysis$Graph$Scope scope) { private static void assignParents(Graph.Scope scope) {
var option = Option.apply(scope); var option = Option.apply(scope);
scope scope
.childScopes() .childScopes()

View File

@ -1,12 +1,7 @@
package org.enso.compiler.context package org.enso.compiler.context
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph import org.enso.compiler.pass.analyse.DataflowAnalysis
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{ import org.enso.compiler.pass.analyse.alias.{Graph => AliasGraph}
Id,
Occurrence,
Scope => AliasScope
}
import org.enso.compiler.pass.analyse.{AliasAnalysis, DataflowAnalysis}
import scala.jdk.CollectionConverters._ import scala.jdk.CollectionConverters._
@ -33,19 +28,19 @@ import scala.jdk.CollectionConverters._
*/ */
class LocalScope( class LocalScope(
final val parentScope: Option[LocalScope], final val parentScope: Option[LocalScope],
final val aliasingGraph: AliasAnalysis.Graph, final val aliasingGraph: AliasGraph,
final val scope: AliasAnalysis.Graph.Scope, final val scope: AliasGraph.Scope,
final val dataflowInfo: DataflowAnalysis.Metadata, final val dataflowInfo: DataflowAnalysis.Metadata,
final val flattenToParent: Boolean = false, final val flattenToParent: Boolean = false,
private val parentFrameSlotIdxs: Map[Graph.Id, Int] = Map() private val parentFrameSlotIdxs: Map[AliasGraph.Id, Int] = Map()
) { ) {
private lazy val localFrameSlotIdxs: Map[Graph.Id, Int] = private lazy val localFrameSlotIdxs: Map[AliasGraph.Id, Int] =
gatherLocalFrameSlotIdxs() gatherLocalFrameSlotIdxs()
/** All frame slot indexes, including local and all the parents. /** All frame slot indexes, including local and all the parents.
* Useful for quick searching for [[FramePointer]] of parent scopes. * Useful for quick searching for [[FramePointer]] of parent scopes.
*/ */
private lazy val allFrameSlotIdxs: Map[Graph.Id, Int] = private lazy val allFrameSlotIdxs: Map[AliasGraph.Id, Int] =
parentFrameSlotIdxs ++ localFrameSlotIdxs parentFrameSlotIdxs ++ localFrameSlotIdxs
/** Creates a new child with a new aliasing scope. /** Creates a new child with a new aliasing scope.
@ -62,7 +57,7 @@ class LocalScope(
* @return a child of this scope * @return a child of this scope
*/ */
def createChild( def createChild(
childScope: AliasScope, childScope: AliasGraph.Scope,
flattenToParent: Boolean = false flattenToParent: Boolean = false
): LocalScope = { ): LocalScope = {
new LocalScope( new LocalScope(
@ -83,7 +78,7 @@ class LocalScope(
* analysis. * analysis.
* @return the frame slot index for `id`. * @return the frame slot index for `id`.
*/ */
def getVarSlotIdx(id: Graph.Id): Int = { def getVarSlotIdx(id: AliasGraph.Id): Int = {
assert( assert(
localFrameSlotIdxs.contains(id), localFrameSlotIdxs.contains(id),
"Cannot find " + id + " in " + localFrameSlotIdxs "Cannot find " + id + " in " + localFrameSlotIdxs
@ -98,7 +93,7 @@ class LocalScope(
* analysis * analysis
* @return the frame pointer for `id`, if it exists * @return the frame pointer for `id`, if it exists
*/ */
def getFramePointer(id: Graph.Id): Option[FramePointer] = { def getFramePointer(id: AliasGraph.Id): Option[FramePointer] = {
aliasingGraph aliasingGraph
.defLinkFor(id) .defLinkFor(id)
.flatMap { link => .flatMap { link =>
@ -126,7 +121,7 @@ class LocalScope(
* indexes in the frame. Takes into account all the * indexes in the frame. Takes into account all the
* internal slots, that are prepended to every frame. * internal slots, that are prepended to every frame.
*/ */
private def gatherLocalFrameSlotIdxs(): Map[Id, Int] = { private def gatherLocalFrameSlotIdxs(): Map[AliasGraph.Id, Int] = {
scope.allDefinitions.zipWithIndex.map { case (definition, i) => scope.allDefinitions.zipWithIndex.map { case (definition, i) =>
definition.id -> (i + LocalScope.internalSlotsSize) definition.id -> (i + LocalScope.internalSlotsSize)
}.toMap }.toMap
@ -139,13 +134,13 @@ class LocalScope(
*/ */
private def flattenBindingsWithLevel( private def flattenBindingsWithLevel(
level: Int level: Int
): Map[Graph.Symbol, FramePointer] = { ): Map[AliasGraph.Symbol, FramePointer] = {
var parentResult: Map[Graph.Symbol, FramePointer] = parentScope var parentResult: Map[AliasGraph.Symbol, FramePointer] = parentScope
.flatMap(scope => Some(scope.flattenBindingsWithLevel(level + 1))) .flatMap(scope => Some(scope.flattenBindingsWithLevel(level + 1)))
.getOrElse(Map()) .getOrElse(Map())
scope.occurrences.foreach { scope.occurrences.foreach {
case x: Occurrence.Def => case x: AliasGraph.Occurrence.Def =>
parentResult += x.symbol -> new FramePointer( parentResult += x.symbol -> new FramePointer(
level, level,
allFrameSlotIdxs(x.id) allFrameSlotIdxs(x.id)
@ -166,7 +161,7 @@ object LocalScope {
* @return a defaulted local scope * @return a defaulted local scope
*/ */
def root: LocalScope = { def root: LocalScope = {
val graph = new AliasAnalysis.Graph val graph = new AliasGraph
new LocalScope( new LocalScope(
None, None,
graph, graph,

View File

@ -78,7 +78,7 @@ object AutomaticParallelism extends IRPass {
ir: Expression, ir: Expression,
parallelismStatus: ParallelismStatus, parallelismStatus: ParallelismStatus,
id: Int, id: Int,
assignment: Option[AliasAnalysis.Graph.Id], assignment: Option[alias.Graph.Id],
dependencies: Set[Int], dependencies: Set[Int],
blockAssignment: Option[BlockAssignment] blockAssignment: Option[BlockAssignment]
) )
@ -215,7 +215,7 @@ object AutomaticParallelism extends IRPass {
AliasAnalysis, AliasAnalysis,
"Alias analysis left a binding behind" "Alias analysis left a binding behind"
) )
.asInstanceOf[AliasAnalysis.Info.Occurrence] .asInstanceOf[alias.Info.Occurrence]
line.copy(assignment = Some(aaInfo.id)) line.copy(assignment = Some(aaInfo.id))
case _ => line case _ => line
} }
@ -233,7 +233,7 @@ object AutomaticParallelism extends IRPass {
n n
} }
.flatMap(_.getMetadata(AliasAnalysis)) .flatMap(_.getMetadata(AliasAnalysis))
.collect { case occ: AliasAnalysis.Info.Occurrence => .collect { case occ: alias.Info.Occurrence =>
occ occ
} }
.flatMap(occ => occ.graph.defLinkFor(occ.id)) .flatMap(occ => occ.graph.defLinkFor(occ.id))

View File

@ -548,7 +548,7 @@ case object DataflowAnalysis extends IRPass {
"Name occurrence with missing aliasing information." "Name occurrence with missing aliasing information."
) )
) )
.asInstanceOf[AliasAnalysis.Info.Occurrence] .asInstanceOf[alias.Info.Occurrence]
name match { name match {
case _: Name.Blank => case _: Name.Blank =>
@ -560,7 +560,7 @@ case object DataflowAnalysis extends IRPass {
val key: DependencyInfo.Type = defIdForName match { val key: DependencyInfo.Type = defIdForName match {
case Some(defLink) => case Some(defLink) =>
aliasInfo.graph.getOccurrence(defLink.target) match { aliasInfo.graph.getOccurrence(defLink.target) match {
case Some(AliasAnalysis.Graph.Occurrence.Def(_, _, id, ext, _)) => case Some(alias.Graph.Occurrence.Def(_, _, id, ext, _)) =>
DependencyInfo.Type.Static(id, ext) DependencyInfo.Type.Static(id, ext)
case _ => case _ =>
DependencyInfo.Type.Dynamic(name.name, None) DependencyInfo.Type.Dynamic(name.name, None)

View File

@ -202,7 +202,7 @@ case object DemandAnalysis extends IRPass {
AliasAnalysis, AliasAnalysis,
"Missing alias occurrence information for a name usage" "Missing alias occurrence information for a name usage"
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[alias.Info.Occurrence]
aliasInfo.graph.defLinkFor(aliasInfo.id).isDefined aliasInfo.graph.defLinkFor(aliasInfo.id).isDefined
} }

View File

@ -0,0 +1,717 @@
package org.enso.compiler.pass.analyse.alias
import org.enso.compiler.core.{CompilerError, ExternalID, Identifier}
import org.enso.syntax.text.Debug
import org.enso.compiler.pass.analyse.alias.Graph.{Occurrence, Scope}
import java.util.UUID
import scala.collection.mutable
import scala.reflect.ClassTag
/** A graph containing aliasing information for a given root scope in Enso. */
sealed class Graph extends Serializable {
var rootScope: Graph.Scope = new Graph.Scope()
var links: Set[Graph.Link] = Set()
var nextIdCounter = 0
private var globalSymbols: Map[Graph.Symbol, Occurrence.Global] =
Map()
/** @return a deep structural copy of `this` */
def deepCopy(
scope_mapping: mutable.Map[Scope, Scope] = mutable.Map()
): Graph = {
val copy = new Graph
copy.rootScope = this.rootScope.deepCopy(scope_mapping)
copy.links = this.links
copy.globalSymbols = this.globalSymbols
copy.nextIdCounter = this.nextIdCounter
copy
}
/** Registers a requested global symbol in the aliasing scope.
*
* @param sym the symbol occurrence
*/
def addGlobalSymbol(sym: Occurrence.Global): Unit = {
if (!globalSymbols.contains(sym.symbol)) {
globalSymbols = globalSymbols + (sym.symbol -> sym)
}
}
/** Creates a deep copy of the aliasing graph structure.
*
* @return a copy of the graph structure
*/
def copy: Graph = {
val graph = new Graph
graph.links = links
graph.rootScope = rootScope.deepCopy(mutable.Map())
graph.nextIdCounter = nextIdCounter
graph
}
/** Determines whether `this` is equal to `obj`.
*
* @param obj the object to compare against.
* @return `true` if `this == obj`, otherwise `false`
*/
override def equals(obj: Any): Boolean =
obj match {
case that: Graph =>
(this.links == that.links) && (this.rootScope == that.rootScope)
case _ => false
}
/** Generates a new identifier for a node in the graph.
*
* @return a unique identifier for this graph
*/
def nextId(): Graph.Id = {
val nextId = nextIdCounter
nextIdCounter += 1
nextId
}
/** Resolves any links for the given usage of a symbol, assuming the symbol
* is a local variable.
*
* @param occurrence the symbol usage
* @return the link, if it exists
*/
def resolveLocalUsage(
occurrence: Graph.Occurrence.Use
): Option[Graph.Link] = {
scopeFor(occurrence.id).flatMap(_.resolveUsage(occurrence).map { link =>
links += link
link
})
}
/** Resolves any links for the given usage of a symbol, assuming the symbol
* is global (i.e. method, constructor etc.)
*
* @param occurrence the symbol usage
* @return the link, if it exists
*/
def resolveGlobalUsage(
occurrence: Graph.Occurrence.Use
): Option[Graph.Link] = {
scopeFor(occurrence.id) match {
case Some(scope) =>
globalSymbols
.get(occurrence.symbol)
.map(g => Graph.Link(occurrence.id, scope.scopesToRoot + 1, g.id))
case None => None
}
}
/** Returns a string representation of the graph.
*
* @return a string representation of `this`
*/
override def toString: String =
s"Graph(links = $links, rootScope = $rootScope)"
/** Pretty prints the graph.
*
* @return a pretty-printed string representation of the graph
*/
def pprint: String = {
val original = toString
Debug.pretty(original)
}
/** Gets all links in which the provided `id` is a participant.
*
* @param id the identifier for the symbol
* @return a list of links in which `id` occurs
*/
def linksFor(id: Graph.Id): Set[Graph.Link] = {
links.filter(l => l.source == id || l.target == id)
}
/** Finds all links in the graph where `symbol` appears in the role
* specified by `T`.
*
* @param symbol the symbol to find links for
* @tparam T the role in which `symbol` should occur
* @return a set of all links in which `symbol` occurs with role `T`
*/
def linksFor[T <: Occurrence: ClassTag](
symbol: Graph.Symbol
): Set[Graph.Link] = {
val idsForSym = rootScope.symbolToIds[T](symbol)
links.filter(l =>
idsForSym.contains(l.source) || idsForSym.contains(l.target)
)
}
/** Obtains the occurrence for a given ID, from whichever scope in which it
* occurs.
*
* @param id the occurrence identifier
* @return the occurrence for `id`, if it exists
*/
def getOccurrence(id: Graph.Id): Option[Occurrence] =
scopeFor(id).flatMap(_.getOccurrence(id))
/** Gets the link from an id to the definition of the symbol it represents.
*
* @param id the identifier to find the definition link for
* @return the definition link for `id` if it exists
*/
def defLinkFor(id: Graph.Id): Option[Graph.Link] = {
linksFor(id).find { edge =>
val occ = getOccurrence(edge.target)
occ match {
case Some(Occurrence.Def(_, _, _, _, _)) => true
case _ => false
}
}
}
/** Gets the scope where a given ID is defined in the graph.
*
* @param id the id to find the scope for
* @return the scope where `id` occurs
*/
def scopeFor(id: Graph.Id): Option[Graph.Scope] = {
rootScope.scopeFor(id)
}
/** Finds the scopes in which a name occurs with a given role.
*
* @param symbol the symbol
* @tparam T the role in which `symbol` occurs
* @return all the scopes where `symbol` occurs with role `T`
*/
def scopesFor[T <: Graph.Occurrence: ClassTag](
symbol: Graph.Symbol
): List[Graph.Scope] = {
rootScope.scopesForSymbol[T](symbol)
}
/** Counts the number of scopes in this scope.
*
* @return the number of scopes that are either this scope or children of
* it
*/
def numScopes: Int = {
rootScope.scopeCount
}
/** Determines the maximum nesting depth of scopes through this scope.
*
* @return the maximum nesting depth of scopes through this scope.
*/
def nesting: Int = {
rootScope.maxNesting
}
/** Determines if the provided ID is capable of shadowing other bindings
*
* @param id the occurrence identifier
* @return `true` if `id` shadows other bindings, otherwise `false`
*/
def canShadow(id: Graph.Id): Boolean = {
scopeFor(id)
.flatMap(
_.getOccurrence(id).flatMap {
case d: Occurrence.Def => Some(d)
case _ => None
}
)
.isDefined
}
/** Computes the bindings that are shadowed by the binding with the provided
* `definition`.
*
* Please note that just because [[canShadow]] states that an identifier is
* _capable_ of shadowing, that does not mean that it is necessarily known
* to do so.
*
* @param definition the definition to find the 'shadowees' of
* @return the bindings shadowed by `definition`
*/
def knownShadowedDefinitions(
definition: Occurrence
): Set[Graph.Occurrence] = {
def getShadowedIds(
scope: Graph.Scope
): Set[Graph.Occurrence] = {
scope.occurrences.collect {
case d: Occurrence.Def if d.symbol == definition.symbol => d
case g: Occurrence.Global if g.symbol == definition.symbol => g
} ++ scope.parent.map(getShadowedIds).getOrElse(Set())
}
definition match {
case d: Occurrence.Def =>
scopeFor(d.id).flatMap(_.parent) match {
case Some(scope) => getShadowedIds(scope) // + globals
case None => Set()
}
case _: Occurrence.Global => Set()
case _: Occurrence.Use => Set()
}
}
/** Determines if the provided id is linked to a binding that shadows
* another binding.
*
* @param id the identifier to check
* @return `true` if the definition of the symbol for `id` shadows another
* binding for the same symbol, `false`, otherwise
*/
def linkedToShadowingBinding(id: Graph.Id): Boolean = {
defLinkFor(id).isDefined
}
/** Gets all symbols defined in the graph.
*
* @return the set of symbols defined in this graph
*/
def symbols: Set[Graph.Symbol] = {
rootScope.symbols
}
/** Goes from a symbol to all identifiers that relate to that symbol in
* the role specified by `T`.
*
* @param symbol the symbol to find identifiers for
* @tparam T the role in which `symbol` should occur
* @return a list of identifiers for that symbol
*/
def symbolToIds[T <: Occurrence: ClassTag](
symbol: Graph.Symbol
): List[Graph.Id] = {
rootScope.symbolToIds[T](symbol)
}
/** Goes from an identifier to the associated symbol.
*
* @param id the identifier of an occurrence
* @return the symbol associated with `id`, if it exists
*/
def idToSymbol(
id: Graph.Id
): Option[Graph.Symbol] = {
rootScope.idToSymbol(id)
}
}
object Graph {
/** The type of symbols on the graph. */
type Symbol = String
/** The type of identifiers on the graph. */
type Id = Int
/** A representation of a local scope in Enso.
*
* @param childScopes all scopes that are _direct_ children of `this`
* @param occurrences all symbol occurrences in `this` scope
* @param allDefinitions all definitions in this scope, including synthetic ones.
* Note that there may not be a link for all these definitions.
*/
sealed class Scope(
var childScopes: List[Scope] = List(),
var occurrences: Set[Occurrence] = Set(),
var allDefinitions: List[Occurrence.Def] = List()
) extends Serializable {
var parent: Option[Scope] = None
/** Counts the number of scopes from this scope to the root.
*
* This count includes the root scope, but not the current scope.
*
* @return the number of scopes from this scope to the root
*/
def scopesToRoot: Int = {
parent.flatMap(scope => Some(scope.scopesToRoot + 1)).getOrElse(0)
}
/** Sets the parent of the scope.
*
* The parent scope must not be redefined.
*
* @return this scope with parent scope set
*/
def withParent(parentScope: Scope): this.type = {
assert(parent.isEmpty)
this.parent = Some(parentScope)
this
}
/** Creates a structural copy of this scope, ensuring that replicated
* scopes are memoised.
*
* @return a copy of `this`
*/
def deepCopy(
mapping: mutable.Map[Scope, Scope] = mutable.Map()
): Scope = {
mapping.get(this) match {
case Some(newCorrespondingScope) => newCorrespondingScope
case None =>
val childScopeCopies: mutable.ListBuffer[Scope] =
mutable.ListBuffer()
this.childScopes.foreach(scope =>
childScopeCopies += scope.deepCopy(mapping)
)
val newScope =
new Scope(childScopeCopies.toList, occurrences, allDefinitions)
mapping.put(this, newScope)
newScope
}
}
/** Checks whether `this` is equal to `obj`.
*
* @param obj the object to compare `this` against
* @return `true` if `this == obj`, otherwise `false`
*/
override def equals(obj: Any): Boolean =
obj match {
case that: Scope =>
if (this.childScopes.length == that.childScopes.length) {
val childScopesEqual =
this.childScopes.zip(that.childScopes).forall(t => t._1 == t._2)
val occurrencesEqual = this.occurrences == that.occurrences
childScopesEqual && occurrencesEqual
} else {
false
}
case _ => false
}
/** Creates and returns a scope that is a child of this one.
*
* @return a scope that is a child of `this`
*/
def addChild(): Scope = {
val scope = new Scope()
scope.parent = Some(this)
childScopes ::= scope
scope
}
/** Adds the specified symbol occurrence to this scope.
*
* @param occurrence the occurrence to add
*/
def add(occurrence: Occurrence): Unit = {
occurrences += occurrence
}
/** Adds a definition, including a definition with synthetic name, without
* any links.
*
* @param definition The definition to add.
*/
def addDefinition(definition: Occurrence.Def): Unit = {
allDefinitions = allDefinitions ++ List(definition)
}
/** Finds an occurrence for the provided ID in the current scope, if it
* exists.
*
* @param id the occurrence identifier
* @return the occurrence for `id`, if it exists
*/
def getOccurrence(id: Graph.Id): Option[Occurrence] = {
occurrences.find(o => o.id == id)
}
/** Finds any occurrences for the provided symbol in the current scope, if
* it exists.
*
* @param symbol the symbol of the occurrence
* @tparam T the role for the symbol
* @return the occurrences for `name`, if they exist
*/
def getOccurrences[T <: Occurrence: ClassTag](
symbol: Graph.Symbol
): Set[Occurrence] = {
occurrences.collect {
case o: T if o.symbol == symbol => o
}
}
/** Unsafely gets the occurrence for the provided ID in the current scope.
*
* Please note that this will crash if the ID is not defined in this
* scope.
*
* @param id the occurrence identifier
* @return the occurrence for `id`
*/
def unsafeGetOccurrence(id: Graph.Id): Occurrence = {
getOccurrence(id).get
}
/** Checks whether a symbol occurs in a given role in the current scope.
*
* @param symbol the symbol to check for
* @tparam T the role for it to occur in
* @return `true` if `symbol` occurs in role `T` in this scope, `false`
* otherwise
*/
def hasSymbolOccurrenceAs[T <: Occurrence: ClassTag](
symbol: Graph.Symbol
): Boolean = {
occurrences.collect { case x: T if x.symbol == symbol => x }.nonEmpty
}
/** Resolves usages of symbols into links where possible, creating an edge
* from the usage site to the definition site.
*
* @param occurrence the symbol usage
* @param parentCounter the number of scopes that the link has traversed
* @return the link from `occurrence` to the definition of that symbol, if it
* exists
*/
def resolveUsage(
occurrence: Graph.Occurrence.Use,
parentCounter: Int = 0
): Option[Graph.Link] = {
val definition = occurrences.find {
case Graph.Occurrence.Def(_, name, _, _, _) =>
name == occurrence.symbol
case _ => false
}
definition match {
case None =>
parent.flatMap(_.resolveUsage(occurrence, parentCounter + 1))
case Some(target) =>
Some(Graph.Link(occurrence.id, parentCounter, target.id))
}
}
/** Creates a string representation of the scope.
*
* @return a string representation of `this`
*/
override def toString: String =
s"Scope(occurrences = $occurrences, childScopes = $childScopes)"
/** Counts the number of scopes in this scope.
*
* @return the number of scopes that are either this scope or children of
* it
*/
def scopeCount: Int = {
childScopes.map(_.scopeCount).sum + 1
}
/** Determines the maximum nesting depth of scopes through this scope.
*
* @return the maximum nesting depth of scopes through this scope.
*/
def maxNesting: Int = {
childScopes.map(_.maxNesting).foldLeft(0)(Math.max) + 1
}
/** Gets the scope where a given ID is defined in the graph.
*
* @param id the id to find the scope for
* @return the scope where `id` occurs
*/
def scopeFor(id: Graph.Id): Option[Scope] = {
val possibleCandidates = occurrences.filter(o => o.id == id)
if (possibleCandidates.isEmpty) {
if (childScopes.isEmpty) {
None
} else {
var childCandidate: Scope = null
val iter = childScopes.iterator
var moreThanOne = false
while (iter.hasNext && !moreThanOne) {
iter.next().scopeFor(id) match {
case Some(s) =>
if (childCandidate == null) {
childCandidate = s
} else {
moreThanOne = true
}
case None =>
}
}
if (childCandidate == null) {
None
} else if (moreThanOne) {
throw new CompilerError(s"ID $id defined in multiple scopes.")
} else {
Some(childCandidate)
}
}
} else if (possibleCandidates.size == 1) {
Some(this)
} else {
throw new CompilerError(s"Multiple occurrences found for ID $id.")
}
}
/** Gets the n-th parent of `this` scope.
*
* @param n the number of scopes to walk up
* @return the n-th parent of `this` scope, if present
*/
def nThParent(n: Int): Option[Scope] = {
if (n == 0) Some(this) else this.parent.flatMap(_.nThParent(n - 1))
}
/** Finds the scopes in which a symbol occurs with a given role.
*
* Users of this function _must_ explicitly specify `T`, otherwise the
* results will be an empty list.
*
* @param symbol the symbol
* @tparam T the role in which `name` occurs
* @return all the scopes where `name` occurs with role `T`
*/
def scopesForSymbol[T <: Occurrence: ClassTag](
symbol: Graph.Symbol
): List[Scope] = {
val occursInThisScope = hasSymbolOccurrenceAs[T](symbol)
val occurrencesInChildScopes =
childScopes.flatMap(_.scopesForSymbol[T](symbol))
if (occursInThisScope) {
this +: occurrencesInChildScopes
} else {
occurrencesInChildScopes
}
}
/** Gets the set of all symbols in this scope and its children.
*
* @return the set of symbols
*/
def symbols: Set[Graph.Symbol] = {
val symbolsInThis = occurrences.map(_.symbol)
val symbolsInChildScopes = childScopes.flatMap(_.symbols)
symbolsInThis ++ symbolsInChildScopes
}
/** Goes from a symbol to all identifiers that relate to that symbol in
* the role specified by `T`.
*
* @param symbol the symbol to find identifiers for
* @tparam T the role in which `symbol` should occur
* @return a list of identifiers for that symbol
*/
def symbolToIds[T <: Occurrence: ClassTag](
symbol: Graph.Symbol
): List[Graph.Id] = {
val scopes =
scopesForSymbol[T](symbol).flatMap(_.getOccurrences[T](symbol))
scopes.map(_.id)
}
/** Goes from an identifier to the associated symbol.
*
* @param id the identifier of an occurrence
* @return the symbol associated with `id`, if it exists
*/
def idToSymbol(
id: Graph.Id
): Option[Graph.Symbol] = {
scopeFor(id).flatMap(_.getOccurrence(id)).map(_.symbol)
}
/** Checks if `this` scope is a child of the provided `scope`.
*
* @param scope the potential parent scope
* @return `true` if `this` is a child of `scope`, otherwise `false`
*/
def isChildOf(scope: Scope): Boolean = {
val isDirectChildOf = scope.childScopes.contains(this)
val isChildOfChildren = scope.childScopes
.map(scope => this.isChildOf(scope))
.foldLeft(false)(_ || _)
isDirectChildOf || isChildOfChildren
}
}
/** A link in the [[Graph]].
*
* The source of the link should always be an [[Occurrence.Use]] while the
* target of the link should always be an [[Occurrence.Def]].
*
* @param source the source ID of the link in the graph
* @param scopeCount the number of scopes that the link traverses
* @param target the target ID of the link in the graph
*/
sealed case class Link(source: Id, scopeCount: Int, target: Id)
extends Serializable
/** An occurrence of a given symbol in the aliasing graph. */
sealed trait Occurrence extends Serializable {
val id: Id
val symbol: Graph.Symbol
}
object Occurrence {
/** The definition of a symbol in the aliasing graph.
*
* @param id the identifier of the name in the graph
* @param symbol the text of the name
* @param identifier the identifier of the symbol
* @param externalId the external identifier for the IR node defining
* the symbol
* @param isLazy whether or not the symbol is defined as lazy
*/
sealed case class Def(
override val id: Id,
override val symbol: Graph.Symbol,
identifier: UUID @Identifier,
externalId: Option[UUID @ExternalID],
isLazy: Boolean = false
) extends Occurrence
/** A usage of a symbol in the aliasing graph
*
* Name usages _need not_ correspond to name definitions, as dynamic
* symbol resolution means that a name used at runtime _may not_ be
* statically visible in the scope.
*
* @param id the identifier of the name in the graph
* @param symbol the text of the name
* @param identifier the identifier of the symbol
* @param externalId the external identifier for the IR node defining
* the symbol
*/
sealed case class Use(
override val id: Id,
override val symbol: Graph.Symbol,
identifier: UUID @Identifier,
externalId: Option[UUID @ExternalID]
) extends Occurrence
// TODO [AA] At some point the analysis should make use of these.
/** Represents a global symbol that has been _asked for_ in the program.
*
* @param id the identifier of the name in the graph
* @param symbol the text of the name
*/
sealed case class Global(
override val id: Id,
override val symbol: Graph.Symbol
) extends Occurrence
}
}

View File

@ -0,0 +1,89 @@
package org.enso.compiler.pass.analyse.alias
import org.enso.compiler.pass.IRPass
/** Information about the aliasing state for a given IR node. */
sealed trait Info extends IRPass.IRMetadata {
/** The aliasing graph. */
val graph: Graph
}
object Info {
sealed trait Scope extends Info
object Scope {
/** Aliasing information for a root scope.
*
* A root scope has a 1:1 correspondence with a top-level binding.
*
* @param graph the graph containing the alias information for that node
*/
sealed case class Root(override val graph: Graph) extends Scope {
override val metadataName: String = "Info.Scope.Root"
/** @inheritdoc */
override def prepareForSerialization(
compiler: Compiler
): Root = this
/** @inheritdoc */
override def restoreFromSerialization(
compiler: Compiler
): Option[Root] = Some(this)
/** @inheritdoc */
override def duplicate(): Option[IRPass.IRMetadata] = None
}
/** Aliasing information about a child scope.
*
* @param graph the graph
* @param scope the child scope in `graph`
*/
sealed case class Child(
override val graph: Graph,
scope: Graph.Scope
) extends Scope {
override val metadataName: String = "Info.Scope.Child"
/** @inheritdoc */
override def prepareForSerialization(
compiler: Compiler
): Child = this
/** @inheritdoc */
override def restoreFromSerialization(
compiler: Compiler
): Option[Child] = Some(this)
/** @inheritdoc */
override def duplicate(): Option[IRPass.IRMetadata] = None
}
}
/** Aliasing information for a piece of [[IR]] that is contained within a
* [[Scope]].
*
* @param graph the graph in which this IR node can be found
* @param id the identifier of this IR node in `graph`
*/
sealed case class Occurrence(
override val graph: Graph,
id: Graph.Id
) extends Info {
override val metadataName: String = "Info.Occurrence"
/** @inheritdoc */
override def prepareForSerialization(
compiler: Compiler
): Occurrence = this
/** @inheritdoc */
override def restoreFromSerialization(
compiler: Compiler
): Option[Occurrence] = Some(this)
/** @inheritdoc */
override def duplicate(): Option[IRPass.IRMetadata] = None
}
}

View File

@ -16,6 +16,7 @@ import org.enso.compiler.core.ir.expression.{errors, warnings, Case, Foreign}
import org.enso.compiler.core.CompilerError import org.enso.compiler.core.CompilerError
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.AliasAnalysis import org.enso.compiler.pass.analyse.AliasAnalysis
import org.enso.compiler.pass.analyse.alias.{Info => AliasInfo}
import org.enso.compiler.pass.desugar._ import org.enso.compiler.pass.desugar._
import org.enso.compiler.pass.optimise.LambdaConsolidate import org.enso.compiler.pass.optimise.LambdaConsolidate
import org.enso.compiler.pass.resolve.{ExpressionAnnotations, IgnoredBindings} import org.enso.compiler.pass.resolve.{ExpressionAnnotations, IgnoredBindings}
@ -109,7 +110,7 @@ case object UnusedBindings extends IRPass {
AliasAnalysis, AliasAnalysis,
"Aliasing information is required for linting." "Aliasing information is required for linting."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
if (!isIgnored && !isUsed) { if (!isIgnored && !isUsed) {
@ -188,7 +189,7 @@ case object UnusedBindings extends IRPass {
"Aliasing information missing from function argument but is " + "Aliasing information missing from function argument but is " +
"required for linting." "required for linting."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
argument match { argument match {
@ -270,7 +271,7 @@ case object UnusedBindings extends IRPass {
"Aliasing information missing from pattern but is " + "Aliasing information missing from pattern but is " +
"required for linting." "required for linting."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
if (!isIgnored && !isUsed) { if (!isIgnored && !isUsed) {
@ -300,7 +301,7 @@ case object UnusedBindings extends IRPass {
"Aliasing information missing from pattern but is " + "Aliasing information missing from pattern but is " +
"required for linting." "required for linting."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
if (!isIgnored && !isUsed) { if (!isIgnored && !isUsed) {

View File

@ -22,6 +22,10 @@ import org.enso.compiler.pass.analyse.{
DemandAnalysis, DemandAnalysis,
TailCall TailCall
} }
import org.enso.compiler.pass.analyse.alias.{
Graph => AliasGraph,
Info => AliasInfo
}
import org.enso.compiler.pass.desugar._ import org.enso.compiler.pass.desugar._
import org.enso.compiler.pass.resolve.IgnoredBindings import org.enso.compiler.pass.resolve.IgnoredBindings
@ -150,7 +154,7 @@ case object LambdaConsolidate extends IRPass {
AliasAnalysis, AliasAnalysis,
"Missing aliasing information for an argument definition" "Missing aliasing information for an argument definition"
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
shadowedBindingIds.contains(aliasInfo.id) shadowedBindingIds.contains(aliasInfo.id)
} }
@ -345,7 +349,7 @@ case object LambdaConsolidate extends IRPass {
*/ */
def getShadowedBindingIds( def getShadowedBindingIds(
args: List[DefinitionArgument] args: List[DefinitionArgument]
): Set[AliasAnalysis.Graph.Id] = { ): Set[AliasGraph.Id] = {
args args
.map { case spec: DefinitionArgument.Specified => .map { case spec: DefinitionArgument.Specified =>
val aliasInfo = val aliasInfo =
@ -354,13 +358,13 @@ case object LambdaConsolidate extends IRPass {
AliasAnalysis, AliasAnalysis,
"Missing aliasing information for an argument definition." "Missing aliasing information for an argument definition."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
aliasInfo.graph aliasInfo.graph
.getOccurrence(aliasInfo.id) .getOccurrence(aliasInfo.id)
.flatMap(occ => Some(aliasInfo.graph.knownShadowedDefinitions(occ))) .flatMap(occ => Some(aliasInfo.graph.knownShadowedDefinitions(occ)))
.getOrElse(Set()) .getOrElse(Set())
} }
.foldLeft(Set[AliasAnalysis.Graph.Occurrence]())(_ ++ _) .foldLeft(Set[AliasGraph.Occurrence]())(_ ++ _)
.map(_.id) .map(_.id)
} }
@ -382,7 +386,7 @@ case object LambdaConsolidate extends IRPass {
AliasAnalysis, AliasAnalysis,
"Missing aliasing information for an argument definition." "Missing aliasing information for an argument definition."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
// Empty set is used to indicate that it isn't shadowed // Empty set is used to indicate that it isn't shadowed
val usageIds = val usageIds =
@ -393,7 +397,7 @@ case object LambdaConsolidate extends IRPass {
.map(link => aliasInfo.graph.getOccurrence(link.source)) .map(link => aliasInfo.graph.getOccurrence(link.source))
.collect { .collect {
case Some( case Some(
AliasAnalysis.Graph.Occurrence.Use(_, _, identifier, _) AliasGraph.Occurrence.Use(_, _, identifier, _)
) => ) =>
identifier identifier
} }

View File

@ -26,6 +26,7 @@ import org.enso.compiler.core.Implicits.{AsDiagnostics, AsMetadata}
import org.enso.compiler.core.ir.expression.Application import org.enso.compiler.core.ir.expression.Application
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis} import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
import org.enso.compiler.pass.analyse.alias.{Info => AliasInfo}
import org.enso.compiler.pass.desugar.Imports import org.enso.compiler.pass.desugar.Imports
import org.enso.editions.LibraryName import org.enso.editions.LibraryName
@ -407,7 +408,7 @@ case object FullyQualifiedNames extends IRPass {
AliasAnalysis, AliasAnalysis,
"no alias analysis info on a name" "no alias analysis info on a name"
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val defLink = aliasInfo.graph.defLinkFor(aliasInfo.id) val defLink = aliasInfo.graph.defLinkFor(aliasInfo.id)
defLink.isDefined defLink.isDefined
} }

View File

@ -27,6 +27,7 @@ import org.enso.compiler.core.ConstantsNames
import org.enso.compiler.core.ir.expression.Application import org.enso.compiler.core.ir.expression.Application
import org.enso.compiler.pass.IRPass import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis} import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
import org.enso.compiler.pass.analyse.alias.{Info => AliasInfo}
/** Resolves name occurences in non-pattern contexts. /** Resolves name occurences in non-pattern contexts.
* *
@ -435,7 +436,7 @@ case object GlobalNames extends IRPass {
AliasAnalysis, AliasAnalysis,
"no alias analysis info on a name" "no alias analysis info on a name"
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val defLink = aliasInfo.graph.defLinkFor(aliasInfo.id) val defLink = aliasInfo.graph.defLinkFor(aliasInfo.id)
defLink.isDefined defLink.isDefined
} }

View File

@ -16,8 +16,8 @@ import org.enso.compiler.core.ir.module.scope.Definition
import org.enso.compiler.core.ir.module.scope.definition import org.enso.compiler.core.ir.module.scope.definition
import org.enso.compiler.pass.PassConfiguration._ import org.enso.compiler.pass.PassConfiguration._
import org.enso.compiler.pass.analyse.AliasAnalysis import org.enso.compiler.pass.analyse.AliasAnalysis
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{Link, Occurrence} import org.enso.compiler.pass.analyse.alias.Graph.{Link, Occurrence}
import org.enso.compiler.pass.analyse.AliasAnalysis.{Graph, Info} import org.enso.compiler.pass.analyse.alias.{Graph, Info}
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager} import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
import org.enso.compiler.test.CompilerTest import org.enso.compiler.test.CompilerTest
@ -413,7 +413,7 @@ class AliasAnalysisTest extends CompilerTest {
.members .members
.head .head
val goodMeta = goodAtom.getMetadata(AliasAnalysis) val goodMeta = goodAtom.getMetadata(AliasAnalysis)
val goodGraph = goodMeta.get.unsafeAs[AliasAnalysis.Info.Scope.Root].graph val goodGraph = goodMeta.get.unsafeAs[Info.Scope.Root].graph
val badAtom = val badAtom =
""" """
@ -424,7 +424,7 @@ class AliasAnalysisTest extends CompilerTest {
.members .members
.head .head
val badMeta = badAtom.getMetadata(AliasAnalysis) val badMeta = badAtom.getMetadata(AliasAnalysis)
val badGraph = badMeta.get.unsafeAs[AliasAnalysis.Info.Scope.Root].graph val badGraph = badMeta.get.unsafeAs[Info.Scope.Root].graph
"assign Info.Scope.Root metadata to the atom" in { "assign Info.Scope.Root metadata to the atom" in {
goodMeta shouldBe defined goodMeta shouldBe defined

View File

@ -45,14 +45,17 @@ import org.enso.compiler.data.BindingsMap.{
} }
import org.enso.compiler.data.{BindingsMap, CompilerConfig} import org.enso.compiler.data.{BindingsMap, CompilerConfig}
import org.enso.compiler.exception.BadPatternMatch import org.enso.compiler.exception.BadPatternMatch
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{Scope => AliasScope} import org.enso.compiler.pass.analyse.alias.Graph.{Scope => AliasScope}
import org.enso.compiler.pass.analyse.AliasAnalysis.{Graph => AliasGraph}
import org.enso.compiler.pass.analyse.{ import org.enso.compiler.pass.analyse.{
AliasAnalysis, AliasAnalysis,
BindingAnalysis, BindingAnalysis,
DataflowAnalysis, DataflowAnalysis,
TailCall TailCall
} }
import org.enso.compiler.pass.analyse.alias.{
Graph => AliasGraph,
Info => AliasInfo
}
import org.enso.compiler.pass.resolve.{ import org.enso.compiler.pass.resolve.{
ExpressionAnnotations, ExpressionAnnotations,
GenericAnnotations, GenericAnnotations,
@ -90,7 +93,7 @@ import org.enso.interpreter.node.{
} }
import org.enso.interpreter.runtime.EnsoContext import org.enso.interpreter.runtime.EnsoContext
import org.enso.interpreter.runtime.callable import org.enso.interpreter.runtime.callable
import org.enso.interpreter.runtime.callable.argument.{ArgumentDefinition} import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition
import org.enso.interpreter.runtime.data.atom.{Atom, AtomConstructor} import org.enso.interpreter.runtime.data.atom.{Atom, AtomConstructor}
import org.enso.interpreter.runtime.callable.function.{ import org.enso.interpreter.runtime.callable.function.{
FunctionSchema, FunctionSchema,
@ -104,7 +107,7 @@ import org.enso.interpreter.runtime.callable.{
} }
import org.enso.interpreter.runtime.data.Type import org.enso.interpreter.runtime.data.Type
import org.enso.interpreter.runtime.data.text.Text import org.enso.interpreter.runtime.data.text.Text
import org.enso.interpreter.runtime.scope.{ModuleScope} import org.enso.interpreter.runtime.scope.ModuleScope
import org.enso.interpreter.{Constants, EnsoLanguage} import org.enso.interpreter.{Constants, EnsoLanguage}
import java.math.BigInteger import java.math.BigInteger
@ -259,7 +262,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"No root scope on an atom definition." "No root scope on an atom definition."
) )
.unsafeAs[AliasAnalysis.Info.Scope.Root] .unsafeAs[AliasInfo.Scope.Root]
val dataflowInfo = atomDefn.unsafeGetMetadata( val dataflowInfo = atomDefn.unsafeGetMetadata(
DataflowAnalysis, DataflowAnalysis,
@ -290,7 +293,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"No occurrence on an argument definition." "No occurrence on an argument definition."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val slotIdx = localScope.getVarSlotIdx(occInfo.id) val slotIdx = localScope.getVarSlotIdx(occInfo.id)
argDefs(idx) = arg argDefs(idx) = arg
val readArg = val readArg =
@ -359,7 +362,7 @@ class IrToTruffle(
s"Missing scope information for method " + s"Missing scope information for method " +
s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`." s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
) )
.unsafeAs[AliasAnalysis.Info.Scope.Root] .unsafeAs[AliasInfo.Scope.Root]
val dataflowInfo = methodDef.unsafeGetMetadata( val dataflowInfo = methodDef.unsafeGetMetadata(
DataflowAnalysis, DataflowAnalysis,
"Method definition missing dataflow information." "Method definition missing dataflow information."
@ -595,7 +598,7 @@ class IrToTruffle(
scopeElements.init scopeElements.init
.mkString(Constants.SCOPE_SEPARATOR) .mkString(Constants.SCOPE_SEPARATOR)
) )
.unsafeAs[AliasAnalysis.Info.Scope.Root] .unsafeAs[AliasInfo.Scope.Root]
val dataflowInfo = annotation.unsafeGetMetadata( val dataflowInfo = annotation.unsafeGetMetadata(
DataflowAnalysis, DataflowAnalysis,
"Missing dataflow information for annotation " + "Missing dataflow information for annotation " +
@ -672,7 +675,7 @@ class IrToTruffle(
s"Missing scope information for conversion " + s"Missing scope information for conversion " +
s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`." s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
) )
.unsafeAs[AliasAnalysis.Info.Scope.Root] .unsafeAs[AliasInfo.Scope.Root]
val dataflowInfo = methodDef.unsafeGetMetadata( val dataflowInfo = methodDef.unsafeGetMetadata(
DataflowAnalysis, DataflowAnalysis,
"Method definition missing dataflow information." "Method definition missing dataflow information."
@ -1122,7 +1125,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"Missing scope information on block." "Missing scope information on block."
) )
.unsafeAs[AliasAnalysis.Info.Scope.Child] .unsafeAs[AliasInfo.Scope.Child]
val childFactory = this.createChild("suspended-block", scopeInfo.scope) val childFactory = this.createChild("suspended-block", scopeInfo.scope)
val childScope = childFactory.scope val childScope = childFactory.scope
@ -1232,7 +1235,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"No scope information on a case branch." "No scope information on a case branch."
) )
.unsafeAs[AliasAnalysis.Info.Scope.Child] .unsafeAs[AliasInfo.Scope.Child]
val childProcessor = this.createChild("case_branch", scopeInfo.scope) val childProcessor = this.createChild("case_branch", scopeInfo.scope)
@ -1601,7 +1604,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"Binding with missing occurrence information." "Binding with missing occurrence information."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
currentVarName = binding.name.name currentVarName = binding.name.name
@ -1625,7 +1628,7 @@ class IrToTruffle(
): RuntimeExpression = { ): RuntimeExpression = {
val scopeInfo = function val scopeInfo = function
.unsafeGetMetadata(AliasAnalysis, "No scope info on a function.") .unsafeGetMetadata(AliasAnalysis, "No scope info on a function.")
.unsafeAs[AliasAnalysis.Info.Scope.Child] .unsafeAs[AliasInfo.Scope.Child]
if (function.body.isInstanceOf[Function]) { if (function.body.isInstanceOf[Function]) {
throw new CompilerError( throw new CompilerError(
@ -1665,7 +1668,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"No occurrence on variable usage." "No occurrence on variable usage."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val framePointer = scope.getFramePointer(useInfo.id) val framePointer = scope.getFramePointer(useInfo.id)
val global = name.getMetadata(GlobalNames) val global = name.getMetadata(GlobalNames)
@ -1946,7 +1949,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"No occurrence on an argument definition." "No occurrence on an argument definition."
) )
.unsafeAs[AliasAnalysis.Info.Occurrence] .unsafeAs[AliasInfo.Occurrence]
val slotIdx = scope.getVarSlotIdx(occInfo.id) val slotIdx = scope.getVarSlotIdx(occInfo.id)
val readArg = val readArg =
@ -2176,7 +2179,7 @@ class IrToTruffle(
AliasAnalysis, AliasAnalysis,
"No scope attached to a call argument." "No scope attached to a call argument."
) )
.unsafeAs[AliasAnalysis.Info.Scope.Child] .unsafeAs[AliasInfo.Scope.Child]
val shouldCreateClosureRootNode = value match { val shouldCreateClosureRootNode = value match {
case _: Name => false case _: Name => false