mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 13:02:07 +03:00
Un-nest AliasAnalysis Info and Graph to allow easier usage from Java (#9451)
This commit is contained in:
parent
de9f2764f9
commit
90b3003312
@ -1,7 +1,8 @@
|
||||
package org.enso.compiler.pass.analyse;
|
||||
|
||||
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.ExpressionAnnotations$;
|
||||
@ -54,12 +55,24 @@ import scala.Option;
|
||||
@Persistable(clazz = GenericAnnotations$.class, id = 1216)
|
||||
@Persistable(clazz = ExpressionAnnotations$.class, id = 1217)
|
||||
@Persistable(clazz = FullyQualifiedNames$.class, id = 1218)
|
||||
@Persistable(clazz = AliasAnalysis$Info$Occurrence.class, id = 1261, allowInlining = false)
|
||||
@Persistable(clazz = AliasAnalysis$Info$Scope$Root.class, id = 1262, allowInlining = false)
|
||||
@Persistable(clazz = AliasAnalysis$Info$Scope$Child.class, id = 1263, allowInlining = false)
|
||||
@Persistable(clazz = AliasAnalysis$Graph$Occurrence$Use.class, id = 1264, allowInlining = false)
|
||||
@Persistable(clazz = AliasAnalysis$Graph$Occurrence$Def.class, id = 1265, allowInlining = false)
|
||||
@Persistable(clazz = AliasAnalysis$Graph$Link.class, id = 1266, allowInlining = false)
|
||||
@Persistable(clazz = Info.Occurrence.class, id = 1261, allowInlining = false)
|
||||
@Persistable(
|
||||
clazz = org.enso.compiler.pass.analyse.alias.Info$Scope$Root.class,
|
||||
id = 1262,
|
||||
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 {
|
||||
private PassPersistance() {}
|
||||
|
||||
@ -106,26 +119,22 @@ public final class PassPersistance {
|
||||
}
|
||||
|
||||
@org.openide.util.lookup.ServiceProvider(service = Persistance.class)
|
||||
public static final class PersistAliasAnalysisGraphScope
|
||||
extends Persistance<org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope> {
|
||||
public static final class PersistAliasAnalysisGraphScope extends Persistance<Graph.Scope> {
|
||||
public PersistAliasAnalysisGraphScope() {
|
||||
super(org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope.class, false, 1267);
|
||||
super(Graph.Scope.class, false, 1267);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope readObject(Input in)
|
||||
throws IOException {
|
||||
protected Graph.Scope readObject(Input in) throws IOException {
|
||||
var childScopes = in.readInline(scala.collection.immutable.List.class);
|
||||
var occurrences = (scala.collection.immutable.Set) in.readObject();
|
||||
var allDefinitions = in.readInline(scala.collection.immutable.List.class);
|
||||
var parent =
|
||||
new org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope(
|
||||
childScopes, occurrences, allDefinitions);
|
||||
var parent = new Graph.Scope(childScopes, occurrences, allDefinitions);
|
||||
var optionParent = Option.apply(parent);
|
||||
childScopes.forall(
|
||||
(object) -> {
|
||||
var ch = (org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope) object;
|
||||
var ch = (Graph.Scope) object;
|
||||
ch.parent_$eq(optionParent);
|
||||
return null;
|
||||
});
|
||||
@ -134,9 +143,7 @@ public final class PassPersistance {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void writeObject(
|
||||
org.enso.compiler.pass.analyse.AliasAnalysis$Graph$Scope obj, Output out)
|
||||
throws IOException {
|
||||
protected void writeObject(Graph.Scope obj, Output out) throws IOException {
|
||||
out.writeInline(scala.collection.immutable.List.class, obj.childScopes());
|
||||
out.writeObject(obj.occurrences());
|
||||
out.writeInline(scala.collection.immutable.List.class, obj.allDefinitions());
|
||||
@ -153,7 +160,7 @@ public final class PassPersistance {
|
||||
protected Graph readObject(Input in) throws IOException {
|
||||
var g = new Graph();
|
||||
|
||||
var rootScope = (AliasAnalysis$Graph$Scope) in.readObject();
|
||||
var rootScope = (Graph.Scope) in.readObject();
|
||||
assignParents(rootScope);
|
||||
g.rootScope_$eq(rootScope);
|
||||
|
||||
@ -175,7 +182,7 @@ public final class PassPersistance {
|
||||
out.writeInt(obj.nextIdCounter());
|
||||
}
|
||||
|
||||
private static void assignParents(AliasAnalysis$Graph$Scope scope) {
|
||||
private static void assignParents(Graph.Scope scope) {
|
||||
var option = Option.apply(scope);
|
||||
scope
|
||||
.childScopes()
|
||||
|
@ -1,12 +1,7 @@
|
||||
package org.enso.compiler.context
|
||||
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{
|
||||
Id,
|
||||
Occurrence,
|
||||
Scope => AliasScope
|
||||
}
|
||||
import org.enso.compiler.pass.analyse.{AliasAnalysis, DataflowAnalysis}
|
||||
import org.enso.compiler.pass.analyse.DataflowAnalysis
|
||||
import org.enso.compiler.pass.analyse.alias.{Graph => AliasGraph}
|
||||
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
@ -33,19 +28,19 @@ import scala.jdk.CollectionConverters._
|
||||
*/
|
||||
class LocalScope(
|
||||
final val parentScope: Option[LocalScope],
|
||||
final val aliasingGraph: AliasAnalysis.Graph,
|
||||
final val scope: AliasAnalysis.Graph.Scope,
|
||||
final val aliasingGraph: AliasGraph,
|
||||
final val scope: AliasGraph.Scope,
|
||||
final val dataflowInfo: DataflowAnalysis.Metadata,
|
||||
final val flattenToParent: Boolean = false,
|
||||
private val parentFrameSlotIdxs: Map[Graph.Id, Int] = Map()
|
||||
final val flattenToParent: Boolean = false,
|
||||
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()
|
||||
|
||||
/** All frame slot indexes, including local and all the parents.
|
||||
* 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
|
||||
|
||||
/** Creates a new child with a new aliasing scope.
|
||||
@ -62,7 +57,7 @@ class LocalScope(
|
||||
* @return a child of this scope
|
||||
*/
|
||||
def createChild(
|
||||
childScope: AliasScope,
|
||||
childScope: AliasGraph.Scope,
|
||||
flattenToParent: Boolean = false
|
||||
): LocalScope = {
|
||||
new LocalScope(
|
||||
@ -83,7 +78,7 @@ class LocalScope(
|
||||
* analysis.
|
||||
* @return the frame slot index for `id`.
|
||||
*/
|
||||
def getVarSlotIdx(id: Graph.Id): Int = {
|
||||
def getVarSlotIdx(id: AliasGraph.Id): Int = {
|
||||
assert(
|
||||
localFrameSlotIdxs.contains(id),
|
||||
"Cannot find " + id + " in " + localFrameSlotIdxs
|
||||
@ -98,7 +93,7 @@ class LocalScope(
|
||||
* analysis
|
||||
* @return the frame pointer for `id`, if it exists
|
||||
*/
|
||||
def getFramePointer(id: Graph.Id): Option[FramePointer] = {
|
||||
def getFramePointer(id: AliasGraph.Id): Option[FramePointer] = {
|
||||
aliasingGraph
|
||||
.defLinkFor(id)
|
||||
.flatMap { link =>
|
||||
@ -126,7 +121,7 @@ class LocalScope(
|
||||
* indexes in the frame. Takes into account all the
|
||||
* 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) =>
|
||||
definition.id -> (i + LocalScope.internalSlotsSize)
|
||||
}.toMap
|
||||
@ -139,13 +134,13 @@ class LocalScope(
|
||||
*/
|
||||
private def flattenBindingsWithLevel(
|
||||
level: Int
|
||||
): Map[Graph.Symbol, FramePointer] = {
|
||||
var parentResult: Map[Graph.Symbol, FramePointer] = parentScope
|
||||
): Map[AliasGraph.Symbol, FramePointer] = {
|
||||
var parentResult: Map[AliasGraph.Symbol, FramePointer] = parentScope
|
||||
.flatMap(scope => Some(scope.flattenBindingsWithLevel(level + 1)))
|
||||
.getOrElse(Map())
|
||||
|
||||
scope.occurrences.foreach {
|
||||
case x: Occurrence.Def =>
|
||||
case x: AliasGraph.Occurrence.Def =>
|
||||
parentResult += x.symbol -> new FramePointer(
|
||||
level,
|
||||
allFrameSlotIdxs(x.id)
|
||||
@ -166,7 +161,7 @@ object LocalScope {
|
||||
* @return a defaulted local scope
|
||||
*/
|
||||
def root: LocalScope = {
|
||||
val graph = new AliasAnalysis.Graph
|
||||
val graph = new AliasGraph
|
||||
new LocalScope(
|
||||
None,
|
||||
graph,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -78,7 +78,7 @@ object AutomaticParallelism extends IRPass {
|
||||
ir: Expression,
|
||||
parallelismStatus: ParallelismStatus,
|
||||
id: Int,
|
||||
assignment: Option[AliasAnalysis.Graph.Id],
|
||||
assignment: Option[alias.Graph.Id],
|
||||
dependencies: Set[Int],
|
||||
blockAssignment: Option[BlockAssignment]
|
||||
)
|
||||
@ -215,7 +215,7 @@ object AutomaticParallelism extends IRPass {
|
||||
AliasAnalysis,
|
||||
"Alias analysis left a binding behind"
|
||||
)
|
||||
.asInstanceOf[AliasAnalysis.Info.Occurrence]
|
||||
.asInstanceOf[alias.Info.Occurrence]
|
||||
line.copy(assignment = Some(aaInfo.id))
|
||||
case _ => line
|
||||
}
|
||||
@ -233,7 +233,7 @@ object AutomaticParallelism extends IRPass {
|
||||
n
|
||||
}
|
||||
.flatMap(_.getMetadata(AliasAnalysis))
|
||||
.collect { case occ: AliasAnalysis.Info.Occurrence =>
|
||||
.collect { case occ: alias.Info.Occurrence =>
|
||||
occ
|
||||
}
|
||||
.flatMap(occ => occ.graph.defLinkFor(occ.id))
|
||||
|
@ -548,7 +548,7 @@ case object DataflowAnalysis extends IRPass {
|
||||
"Name occurrence with missing aliasing information."
|
||||
)
|
||||
)
|
||||
.asInstanceOf[AliasAnalysis.Info.Occurrence]
|
||||
.asInstanceOf[alias.Info.Occurrence]
|
||||
|
||||
name match {
|
||||
case _: Name.Blank =>
|
||||
@ -560,7 +560,7 @@ case object DataflowAnalysis extends IRPass {
|
||||
val key: DependencyInfo.Type = defIdForName match {
|
||||
case Some(defLink) =>
|
||||
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)
|
||||
case _ =>
|
||||
DependencyInfo.Type.Dynamic(name.name, None)
|
||||
|
@ -202,7 +202,7 @@ case object DemandAnalysis extends IRPass {
|
||||
AliasAnalysis,
|
||||
"Missing alias occurrence information for a name usage"
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[alias.Info.Occurrence]
|
||||
|
||||
aliasInfo.graph.defLinkFor(aliasInfo.id).isDefined
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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.pass.IRPass
|
||||
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.optimise.LambdaConsolidate
|
||||
import org.enso.compiler.pass.resolve.{ExpressionAnnotations, IgnoredBindings}
|
||||
@ -109,7 +110,7 @@ case object UnusedBindings extends IRPass {
|
||||
AliasAnalysis,
|
||||
"Aliasing information is required for linting."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
|
||||
|
||||
if (!isIgnored && !isUsed) {
|
||||
@ -188,7 +189,7 @@ case object UnusedBindings extends IRPass {
|
||||
"Aliasing information missing from function argument but is " +
|
||||
"required for linting."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
|
||||
|
||||
argument match {
|
||||
@ -270,7 +271,7 @@ case object UnusedBindings extends IRPass {
|
||||
"Aliasing information missing from pattern but is " +
|
||||
"required for linting."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
|
||||
|
||||
if (!isIgnored && !isUsed) {
|
||||
@ -300,7 +301,7 @@ case object UnusedBindings extends IRPass {
|
||||
"Aliasing information missing from pattern but is " +
|
||||
"required for linting."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
val isUsed = aliasInfo.graph.linksFor(aliasInfo.id).nonEmpty
|
||||
|
||||
if (!isIgnored && !isUsed) {
|
||||
|
@ -22,6 +22,10 @@ import org.enso.compiler.pass.analyse.{
|
||||
DemandAnalysis,
|
||||
TailCall
|
||||
}
|
||||
import org.enso.compiler.pass.analyse.alias.{
|
||||
Graph => AliasGraph,
|
||||
Info => AliasInfo
|
||||
}
|
||||
import org.enso.compiler.pass.desugar._
|
||||
import org.enso.compiler.pass.resolve.IgnoredBindings
|
||||
|
||||
@ -150,7 +154,7 @@ case object LambdaConsolidate extends IRPass {
|
||||
AliasAnalysis,
|
||||
"Missing aliasing information for an argument definition"
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
shadowedBindingIds.contains(aliasInfo.id)
|
||||
}
|
||||
|
||||
@ -345,7 +349,7 @@ case object LambdaConsolidate extends IRPass {
|
||||
*/
|
||||
def getShadowedBindingIds(
|
||||
args: List[DefinitionArgument]
|
||||
): Set[AliasAnalysis.Graph.Id] = {
|
||||
): Set[AliasGraph.Id] = {
|
||||
args
|
||||
.map { case spec: DefinitionArgument.Specified =>
|
||||
val aliasInfo =
|
||||
@ -354,13 +358,13 @@ case object LambdaConsolidate extends IRPass {
|
||||
AliasAnalysis,
|
||||
"Missing aliasing information for an argument definition."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
aliasInfo.graph
|
||||
.getOccurrence(aliasInfo.id)
|
||||
.flatMap(occ => Some(aliasInfo.graph.knownShadowedDefinitions(occ)))
|
||||
.getOrElse(Set())
|
||||
}
|
||||
.foldLeft(Set[AliasAnalysis.Graph.Occurrence]())(_ ++ _)
|
||||
.foldLeft(Set[AliasGraph.Occurrence]())(_ ++ _)
|
||||
.map(_.id)
|
||||
}
|
||||
|
||||
@ -382,7 +386,7 @@ case object LambdaConsolidate extends IRPass {
|
||||
AliasAnalysis,
|
||||
"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
|
||||
val usageIds =
|
||||
@ -393,7 +397,7 @@ case object LambdaConsolidate extends IRPass {
|
||||
.map(link => aliasInfo.graph.getOccurrence(link.source))
|
||||
.collect {
|
||||
case Some(
|
||||
AliasAnalysis.Graph.Occurrence.Use(_, _, identifier, _)
|
||||
AliasGraph.Occurrence.Use(_, _, identifier, _)
|
||||
) =>
|
||||
identifier
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import org.enso.compiler.core.Implicits.{AsDiagnostics, AsMetadata}
|
||||
import org.enso.compiler.core.ir.expression.Application
|
||||
import org.enso.compiler.pass.IRPass
|
||||
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.editions.LibraryName
|
||||
|
||||
@ -407,7 +408,7 @@ case object FullyQualifiedNames extends IRPass {
|
||||
AliasAnalysis,
|
||||
"no alias analysis info on a name"
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
val defLink = aliasInfo.graph.defLinkFor(aliasInfo.id)
|
||||
defLink.isDefined
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import org.enso.compiler.core.ConstantsNames
|
||||
import org.enso.compiler.core.ir.expression.Application
|
||||
import org.enso.compiler.pass.IRPass
|
||||
import org.enso.compiler.pass.analyse.{AliasAnalysis, BindingAnalysis}
|
||||
import org.enso.compiler.pass.analyse.alias.{Info => AliasInfo}
|
||||
|
||||
/** Resolves name occurences in non-pattern contexts.
|
||||
*
|
||||
@ -435,7 +436,7 @@ case object GlobalNames extends IRPass {
|
||||
AliasAnalysis,
|
||||
"no alias analysis info on a name"
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
val defLink = aliasInfo.graph.defLinkFor(aliasInfo.id)
|
||||
defLink.isDefined
|
||||
}
|
||||
|
@ -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.pass.PassConfiguration._
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{Link, Occurrence}
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis.{Graph, Info}
|
||||
import org.enso.compiler.pass.analyse.alias.Graph.{Link, Occurrence}
|
||||
import org.enso.compiler.pass.analyse.alias.{Graph, Info}
|
||||
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
|
||||
import org.enso.compiler.test.CompilerTest
|
||||
|
||||
@ -413,7 +413,7 @@ class AliasAnalysisTest extends CompilerTest {
|
||||
.members
|
||||
.head
|
||||
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 =
|
||||
"""
|
||||
@ -424,7 +424,7 @@ class AliasAnalysisTest extends CompilerTest {
|
||||
.members
|
||||
.head
|
||||
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 {
|
||||
goodMeta shouldBe defined
|
||||
|
@ -45,14 +45,17 @@ import org.enso.compiler.data.BindingsMap.{
|
||||
}
|
||||
import org.enso.compiler.data.{BindingsMap, CompilerConfig}
|
||||
import org.enso.compiler.exception.BadPatternMatch
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis.Graph.{Scope => AliasScope}
|
||||
import org.enso.compiler.pass.analyse.AliasAnalysis.{Graph => AliasGraph}
|
||||
import org.enso.compiler.pass.analyse.alias.Graph.{Scope => AliasScope}
|
||||
import org.enso.compiler.pass.analyse.{
|
||||
AliasAnalysis,
|
||||
BindingAnalysis,
|
||||
DataflowAnalysis,
|
||||
TailCall
|
||||
}
|
||||
import org.enso.compiler.pass.analyse.alias.{
|
||||
Graph => AliasGraph,
|
||||
Info => AliasInfo
|
||||
}
|
||||
import org.enso.compiler.pass.resolve.{
|
||||
ExpressionAnnotations,
|
||||
GenericAnnotations,
|
||||
@ -90,7 +93,7 @@ import org.enso.interpreter.node.{
|
||||
}
|
||||
import org.enso.interpreter.runtime.EnsoContext
|
||||
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.callable.function.{
|
||||
FunctionSchema,
|
||||
@ -104,7 +107,7 @@ import org.enso.interpreter.runtime.callable.{
|
||||
}
|
||||
import org.enso.interpreter.runtime.data.Type
|
||||
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 java.math.BigInteger
|
||||
@ -259,7 +262,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"No root scope on an atom definition."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Root]
|
||||
.unsafeAs[AliasInfo.Scope.Root]
|
||||
|
||||
val dataflowInfo = atomDefn.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
@ -290,7 +293,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"No occurrence on an argument definition."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
val slotIdx = localScope.getVarSlotIdx(occInfo.id)
|
||||
argDefs(idx) = arg
|
||||
val readArg =
|
||||
@ -359,7 +362,7 @@ class IrToTruffle(
|
||||
s"Missing scope information for method " +
|
||||
s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Root]
|
||||
.unsafeAs[AliasInfo.Scope.Root]
|
||||
val dataflowInfo = methodDef.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Method definition missing dataflow information."
|
||||
@ -595,7 +598,7 @@ class IrToTruffle(
|
||||
scopeElements.init
|
||||
.mkString(Constants.SCOPE_SEPARATOR)
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Root]
|
||||
.unsafeAs[AliasInfo.Scope.Root]
|
||||
val dataflowInfo = annotation.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Missing dataflow information for annotation " +
|
||||
@ -672,7 +675,7 @@ class IrToTruffle(
|
||||
s"Missing scope information for conversion " +
|
||||
s"`${methodDef.typeName.map(_.name + ".").getOrElse("")}${methodDef.methodName.name}`."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Root]
|
||||
.unsafeAs[AliasInfo.Scope.Root]
|
||||
val dataflowInfo = methodDef.unsafeGetMetadata(
|
||||
DataflowAnalysis,
|
||||
"Method definition missing dataflow information."
|
||||
@ -1122,7 +1125,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"Missing scope information on block."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Child]
|
||||
.unsafeAs[AliasInfo.Scope.Child]
|
||||
|
||||
val childFactory = this.createChild("suspended-block", scopeInfo.scope)
|
||||
val childScope = childFactory.scope
|
||||
@ -1232,7 +1235,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"No scope information on a case branch."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Child]
|
||||
.unsafeAs[AliasInfo.Scope.Child]
|
||||
|
||||
val childProcessor = this.createChild("case_branch", scopeInfo.scope)
|
||||
|
||||
@ -1601,7 +1604,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"Binding with missing occurrence information."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
|
||||
currentVarName = binding.name.name
|
||||
|
||||
@ -1625,7 +1628,7 @@ class IrToTruffle(
|
||||
): RuntimeExpression = {
|
||||
val scopeInfo = function
|
||||
.unsafeGetMetadata(AliasAnalysis, "No scope info on a function.")
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Child]
|
||||
.unsafeAs[AliasInfo.Scope.Child]
|
||||
|
||||
if (function.body.isInstanceOf[Function]) {
|
||||
throw new CompilerError(
|
||||
@ -1665,7 +1668,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"No occurrence on variable usage."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
|
||||
val framePointer = scope.getFramePointer(useInfo.id)
|
||||
val global = name.getMetadata(GlobalNames)
|
||||
@ -1946,7 +1949,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"No occurrence on an argument definition."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Occurrence]
|
||||
.unsafeAs[AliasInfo.Occurrence]
|
||||
|
||||
val slotIdx = scope.getVarSlotIdx(occInfo.id)
|
||||
val readArg =
|
||||
@ -2176,7 +2179,7 @@ class IrToTruffle(
|
||||
AliasAnalysis,
|
||||
"No scope attached to a call argument."
|
||||
)
|
||||
.unsafeAs[AliasAnalysis.Info.Scope.Child]
|
||||
.unsafeAs[AliasInfo.Scope.Child]
|
||||
|
||||
val shouldCreateClosureRootNode = value match {
|
||||
case _: Name => false
|
||||
|
Loading…
Reference in New Issue
Block a user