-
Notifications
You must be signed in to change notification settings - Fork 323
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Can no longer import Test.Logical_Export.Impl
- Loading branch information
1 parent
6ff9917
commit 42118ac
Showing
3 changed files
with
168 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 150 additions & 0 deletions
150
engine/runtime/src/main/scala/org/enso/compiler/pass/analyse/ImportApiAnalysis.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package org.enso.compiler.pass.analyse | ||
|
||
import org.enso.interpreter.runtime.Module | ||
import org.enso.compiler.context.{InlineContext, ModuleContext} | ||
import org.enso.compiler.core.IR | ||
import org.enso.compiler.data.BindingsMap | ||
import org.enso.compiler.pass.IRPass | ||
import org.enso.compiler.pass.desugar.{ | ||
ComplexType, | ||
FunctionBinding, | ||
GenerateMethodBodies | ||
} | ||
import org.enso.compiler.pass.resolve.{MethodDefinitions, Patterns} | ||
|
||
import scala.annotation.unused | ||
|
||
/** Recognizes all defined bindings in the current module and constructs | ||
* a mapping data structure that can later be used for symbol resolution. | ||
*/ | ||
case object ImportApiAnalysis extends IRPass { | ||
|
||
override type Metadata = BindingsMap | ||
|
||
/** The type of configuration for the pass. */ | ||
override type Config = IRPass.Configuration.Default | ||
|
||
/** The passes that this pass depends _directly_ on to run. */ | ||
override val precursorPasses: Seq[IRPass] = | ||
Seq(ComplexType, FunctionBinding, GenerateMethodBodies) | ||
|
||
/** The passes that are invalidated by running this pass. */ | ||
override val invalidatedPasses: Seq[IRPass] = | ||
Seq(MethodDefinitions, Patterns) | ||
|
||
/** Executes the pass on the provided `ir`, and returns a possibly transformed | ||
* or annotated version of `ir`. | ||
* | ||
* @param ir the Enso IR to process | ||
* @param moduleContext a context object that contains the information needed | ||
* to process a module | ||
* @return `ir`, possibly having made transformations or annotations to that | ||
* IR. | ||
*/ | ||
override def runModule( | ||
ir: IR.Module, | ||
moduleContext: ModuleContext | ||
): IR.Module = { | ||
val map: BindingsMap = | ||
ir.unsafeGetMetadata(BindingAnalysis, "Should exist.") | ||
val forbiddenImports = new java.util.HashMap[String, String] | ||
|
||
map.resolvedImports.map { imp: BindingsMap.ResolvedImport => | ||
val maybeModule = imp.target match { | ||
case rm: BindingsMap.ResolvedModule => | ||
None | ||
rm.module match { | ||
case c: BindingsMap.ModuleReference.Concrete => Some(c.module) | ||
case _ => None | ||
} | ||
case _ => None | ||
} | ||
|
||
maybeModule.map(m => { | ||
val pkg = m.getPackage() | ||
if (moduleContext.module.getPackage() != pkg) { | ||
if (pkg.mainFile != null) { | ||
val found = pkg.findModule("Main") | ||
if (found != null) { | ||
// if the package has Main file, then imports has to go thru the main module | ||
val mainModule = found.asInstanceOf[Module] | ||
if (m != mainModule) { | ||
// if different that Main module is requested, do a check | ||
if (mainModule.getIr == null) { | ||
// if main module IR isn't loaded, then certainly the import didn't go thru Main | ||
forbiddenImports.put( | ||
m.getName().toString(), | ||
mainModule.getName().toString() | ||
) | ||
} else { | ||
val mainMap: BindingsMap = mainModule.getIr | ||
.unsafeGetMetadata(BindingAnalysis, "Should exist.") | ||
val checks = for { | ||
// go thru all re-exported modules in main | ||
(name, modules) <- mainMap.exportedSymbols | ||
module <- modules | ||
} yield { | ||
module match { | ||
case BindingsMap.ResolvedModule( | ||
BindingsMap.ModuleReference.Concrete(allowed) | ||
) => { | ||
// check if one of the exported modules matches the imported one | ||
allowed == m | ||
} | ||
case _ => false | ||
} | ||
} | ||
if (!checks.exists(b => b)) { | ||
// if no re-exported module patches m, report an error | ||
forbiddenImports.put( | ||
m.getName().toString(), | ||
mainModule.getName().toString() | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}) | ||
} | ||
val replace = ir.imports.map(imp => | ||
imp match { | ||
case m: IR.Module.Scope.Import.Module => | ||
val name: String = m.name.name | ||
val pkg = forbiddenImports.get(name) | ||
if (pkg != null) { | ||
IR.Error.ImportExport( | ||
imp, | ||
IR.Error.ImportExport | ||
.SymbolDoesNotExist(name.split("\\.").last, pkg) | ||
) | ||
} else { | ||
m | ||
} | ||
case i => i | ||
} | ||
) | ||
ir.copy(imports = replace) | ||
} | ||
|
||
/** Executes the pass on the provided `ir`, and returns a possibly transformed | ||
* or annotated version of `ir` in an inline context. | ||
* | ||
* @param ir the Enso IR to process | ||
* @param inlineContext a context object that contains the information needed | ||
* for inline evaluation | ||
* @return `ir`, possibly having made transformations or annotations to that | ||
* IR. | ||
*/ | ||
override def runExpression( | ||
ir: IR.Expression, | ||
inlineContext: InlineContext | ||
): IR.Expression = ir | ||
|
||
/** @inheritdoc */ | ||
override def updateMetadataInDuplicate[T <: IR]( | ||
@unused sourceIr: T, | ||
copyOfIr: T | ||
): T = copyOfIr | ||
} |