Ambiguous imports warnings/errors are serializable (#8093)

`AmbgiuousImport` error and `DuplicatedImport` warning must not have `Source` as one of its fields or compiler will crash during a serialization attempt.
Changed the implementation to provide it as a parameter to the `message` method instead.

Fixes #8089
This commit is contained in:
Hubert Plociniczak 2023-10-18 23:51:58 +02:00 committed by GitHub
parent 28fc183f92
commit ab2da9e436
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 160 additions and 89 deletions

View File

@ -199,14 +199,15 @@ final class EnsureCompiledJob(
module: Module,
diagnostic: Diagnostic
): Api.ExecutionResult.Diagnostic = {
val source = module.getSource
Api.ExecutionResult.Diagnostic(
kind,
Option(diagnostic.formattedMessage),
Option(diagnostic.formattedMessage(source)),
Option(module.getPath).map(new File(_)),
diagnostic.location
.map(loc =>
LocationResolver
.locationToRange(loc.location, module.getSource.getCharacters)
.locationToRange(loc.location, source.getCharacters)
),
diagnostic.location
.flatMap(LocationResolver.getExpressionId(module.getIr, _))

View File

@ -1,14 +1,19 @@
package org.enso.compiler.core.ir
import com.oracle.truffle.api.source.Source
/** A representation of various kinds of diagnostic in the IR. */
trait Diagnostic extends Serializable {
/** @return a human-readable description of this error condition.
/** @param source Location of the diagnostic.
* @return a human-readable description of this error condition.
*/
def message: String
def message(source: Source): String
/** @return a human-readable description of this error condition, formatted for immediate reporting. */
def formattedMessage: String = message
/** @param source Location of the diagnostic.
* @return a human-readable description of this error condition, formatted for immediate reporting.
*/
def formattedMessage(source: Source): String = message(source)
/** The location at which the diagnostic occurs. */
val location: Option[IdentifiedLocation]

View File

@ -1,5 +1,6 @@
package org.enso.compiler.core.ir
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.{randomId, ToStringHelper}
@ -75,7 +76,7 @@ sealed case class Empty(
override def children: List[IR] = List()
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
"Empty IR: Please report this as a compiler bug."
/** @inheritdoc */

View File

@ -12,10 +12,9 @@ object Warning {
case class DuplicatedImport(
override val location: Option[IdentifiedLocation],
originalImport: ir.module.scope.Import,
symbolName: String,
source: Source
symbolName: String
) extends Warning {
override def message: String = {
override def message(source: Source): String = {
val originalImportRepr =
originalImport.location match {
case Some(location) =>
@ -35,7 +34,7 @@ object Warning {
*/
case class WrongTco(override val location: Option[IdentifiedLocation])
extends Warning {
override def message: String =
override def message(source: Source): String =
"A @Tail_Call annotation was placed in a non-tail-call position."
override def diagnosticKeys(): Array[Any] = Array()
@ -49,7 +48,7 @@ object Warning {
case class WrongBuiltinMethod(
override val location: Option[IdentifiedLocation]
) extends Warning {
override def message: String =
override def message(source: Source): String =
"A @Builtin_Method annotation allows only the name of the builtin node in the body."
override def diagnosticKeys(): Array[Any] = Array()
@ -68,7 +67,7 @@ object Warning {
) extends Warning {
override val location: Option[IdentifiedLocation] = ir.location
override def message: String =
override def message(source: Source): String =
s"${funName.name}: Self parameter should be declared as the first parameter. Instead its position is: ${paramPosition + 1}."
override def diagnosticKeys(): Array[Any] =
@ -87,7 +86,7 @@ object Warning {
) extends Warning {
override val location: Option[IdentifiedLocation] = ir.location
override def message: String =
override def message(source: Source): String =
s"The expression ${ir.showCode()} could not be parallelised: $reason."
override def diagnosticKeys(): Array[Any] = Array(ir.showCode(), reason)
@ -98,7 +97,7 @@ object Warning {
/** @return a human-readable description of this error condition.
*/
override def message: String =
override def message(source: Source): String =
s"A non-unit type ${ir.name} is used on value level (in ${context})." +
" This is probably an error."

View File

@ -1,6 +1,7 @@
package org.enso.compiler.core.ir
package expression
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR.{randomId, Identifier, ToStringHelper}
import org.enso.compiler.core.ir.Expression
import org.enso.compiler.core.{ir, IR}
@ -107,7 +108,7 @@ object Error {
override def children: List[IR] = List(ir)
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
"InvalidIR: Please report this as a compiler bug."
override def diagnosticKeys(): Array[Any] = Array()

View File

@ -2,6 +2,7 @@ package org.enso.compiler.core.ir
package expression
package errors
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.{randomId, Identifier}
@ -85,7 +86,7 @@ sealed case class Conversion(
s"(Error: ${storedIr.showCode(indent)})"
/** @inheritdoc */
override def message: String = reason.explain
override def message(source: Source): String = reason.explain
override def diagnosticKeys(): Array[Any] = Array(reason.explain)

View File

@ -97,7 +97,7 @@ sealed case class ImportExport(
override def children: List[IR] = List(ir)
/** @inheritdoc */
override def message: String = reason.message
override def message(source: Source): String = reason.message(source)
override def diagnosticKeys(): Array[Any] = Array(reason)
@ -111,9 +111,10 @@ object ImportExport {
*/
sealed trait Reason {
/** @return A human-readable description of the error.
/** @param source Location of the original import/export IR.
* @return A human-readable description of the error.
*/
def message: String
def message(source: Source): String
}
/** Used when the `project` keyword is used in an impossible position.
@ -123,7 +124,7 @@ object ImportExport {
*/
case class ProjectKeywordUsedButNotInProject(statementType: String)
extends Reason {
override def message: String =
override def message(source: Source): String =
s"The `project` keyword was used in an $statementType statement," +
" but the module does not belong to a project."
}
@ -135,7 +136,8 @@ object ImportExport {
*/
case class PackageCouldNotBeLoaded(name: String, reason: String)
extends Reason {
override def message: String = s"Package containing the module $name" +
override def message(source: Source): String =
s"Package containing the module $name" +
s" could not be loaded: $reason"
}
@ -144,14 +146,15 @@ object ImportExport {
* @param name the module name.
*/
case class ModuleDoesNotExist(name: String) extends Reason {
override def message: String = s"The module $name does not exist."
override def message(source: Source): String =
s"The module $name does not exist."
}
case class TypeDoesNotExist(
typeName: String,
moduleName: String
) extends Reason {
override def message: String =
override def message(source: Source): String =
s"The type $typeName does not exist in module $moduleName"
}
@ -159,7 +162,7 @@ object ImportExport {
symbolName: String,
moduleOrTypeName: String
) extends Reason {
override def message: String =
override def message(source: Source): String =
s"The symbol $symbolName (module, type, or constructor) does not exist in $moduleOrTypeName."
}
@ -167,28 +170,28 @@ object ImportExport {
typeName: String,
constructorName: String
) extends Reason {
override def message: String =
override def message(source: Source): String =
s"No such constructor ${constructorName} in type $typeName"
}
case class ExportSymbolsFromPrivateModule(
moduleName: String
) extends Reason {
override def message: String =
override def message(source: Source): String =
s"Cannot export any symbol from module '$moduleName': The module is private"
}
case class ExportPrivateModule(
moduleName: String
) extends Reason {
override def message: String =
override def message(source: Source): String =
s"Cannot export private module '$moduleName'"
}
case class ImportPrivateModule(
moduleName: String
) extends Reason {
override def message: String =
override def message(source: Source): String =
s"Cannot import private module '$moduleName'"
}
@ -198,7 +201,7 @@ object ImportExport {
moduleVisibility: String,
submoduleVisibility: String
) extends Reason {
override def message: String =
override def message(source: Source): String =
s"Cannot export submodule '$submoduleName' of module '$moduleName': " +
s"the submodule is $submoduleVisibility, but the module is $moduleVisibility"
}
@ -210,16 +213,14 @@ object ImportExport {
* @param originalSymbolPath the original symbol path.
* @param symbolName the symbol name that is ambiguous.
* @param symbolPath the symbol path that is different than [[originalSymbolPath]].
* @param source Location of the original import.
*/
case class AmbiguousImport(
originalImport: module.scope.Import,
originalSymbolPath: String,
symbolName: String,
symbolPath: String,
source: Source
symbolPath: String
) extends Reason {
override def message: String = {
override def message(source: Source): String = {
val originalImportRepr =
originalImport.location match {
case Some(location) =>

View File

@ -2,6 +2,7 @@ package org.enso.compiler.core.ir
package expression
package errors
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.{randomId, Identifier}
@ -69,7 +70,7 @@ sealed case class Pattern(
id = if (keepIdentifiers) id else randomId
)
override def message: String = reason.explain
override def message(source: Source): String = reason.explain
override def diagnosticKeys(): Array[Any] = Array(reason)

View File

@ -2,6 +2,7 @@ package org.enso.compiler.core.ir
package expression
package errors
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.{randomId, Identifier}
@ -87,7 +88,7 @@ object Redefined {
this
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
"Methods must have only one definition of the `this` argument, and " +
"it must be the first."
@ -186,7 +187,7 @@ object Redefined {
copy(location = location)
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
s"Method overloads are not supported: ${targetType.map(_.name + ".").getOrElse("")}from " +
s"${sourceType.showCode()} is defined multiple times in this module."
@ -305,7 +306,7 @@ object Redefined {
copy(location = location)
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
s"Method overloads are not supported: ${atomName.map(_.name + ".").getOrElse("")}" +
s"${methodName.name} is defined multiple times in this module."
@ -431,7 +432,7 @@ object Redefined {
copy(location = location)
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
s"Method definitions with the same name as atoms are not supported. " +
s"Method ${methodName.name} clashes with the atom ${atomName.name} in this module."
@ -534,7 +535,7 @@ object Redefined {
copy(location = location)
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
s"Redefining atoms is not supported: ${typeName.name} is " +
s"defined multiple times in this module."
@ -650,7 +651,7 @@ object Redefined {
override def children: List[IR] = List(invalidBinding)
/** @inheritdoc */
override def message: String =
override def message(source: Source): String =
s"Variable ${invalidBinding.name.name} is being redefined."
override def diagnosticKeys(): Array[Any] = Array(

View File

@ -2,6 +2,7 @@ package org.enso.compiler.core.ir
package expression
package errors
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.{randomId, Identifier}
@ -83,10 +84,10 @@ sealed case class Resolution(
override def showCode(indent: Int): String = originalName.showCode(indent)
/** @inheritdoc */
override def message: String = reason.explain(originalName)
override def message(source: Source): String = reason.explain(originalName)
/** @inheritdoc */
override def formattedMessage: String = s"${message}."
override def formattedMessage(source: Source): String = s"${message(source)}."
override def diagnosticKeys(): Array[Any] = Array(reason)

View File

@ -2,6 +2,7 @@ package org.enso.compiler.core.ir
package expression
package errors
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.{randomId, Identifier, ToStringHelper}
@ -89,10 +90,10 @@ sealed case class Syntax(
override def children: List[IR] = List()
/** @inheritdoc */
override def message: String = reason.explanation
override def message(source: Source): String = reason.explanation
/** @inheritdoc */
override def formattedMessage: String = s"${message}."
override def formattedMessage(source: Source): String = s"${message(source)}."
override def diagnosticKeys(): Array[Any] = Array(reason)

View File

@ -2,6 +2,7 @@ package org.enso.compiler.core.ir
package expression
package errors
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
import org.enso.compiler.core.IR.{randomId, Identifier}
@ -17,7 +18,7 @@ sealed trait Unexpected extends Error {
override val location: Option[IdentifiedLocation] = ir.location
/** @inheritdoc */
override def message: String = s"Unexpected $entity."
override def message(source: Source): String = s"Unexpected $entity."
/** @inheritdoc */
override def diagnosticKeys(): Array[Any] = Array(entity)

View File

@ -2,6 +2,7 @@ package org.enso.compiler.core.ir
package expression
package warnings
import com.oracle.truffle.api.source.Source
import org.enso.compiler.core.IR
/** Warnings about shadowing names. */
@ -25,7 +26,7 @@ object Shadowed {
override val shadower: IR,
override val location: Option[IdentifiedLocation]
) extends Shadowed {
override def message: String =
override def message(source: Source): String =
s"The argument $shadowedName is shadowed by $shadower"
override def diagnosticKeys(): Array[Any] =
@ -44,7 +45,7 @@ object Shadowed {
override val shadower: IR,
override val location: Option[IdentifiedLocation]
) extends Shadowed {
override def message: String =
override def message(source: Source): String =
s"The pattern field $shadowedName is shadowed by $shadower."
override def diagnosticKeys(): Array[Any] =
@ -65,7 +66,7 @@ object Shadowed {
override val shadower: IR,
override val location: Option[IdentifiedLocation]
) extends Shadowed {
override def message: String =
override def message(source: Source): String =
s"""Declaration of type $typeName shadows module ${moduleName.name} making it inaccessible via a qualified name."""
override def diagnosticKeys(): Array[Any] =
@ -88,7 +89,7 @@ object Shadowed {
override val shadower: IR,
override val location: Option[IdentifiedLocation]
) extends Shadowed {
override def message: String =
override def message(source: Source): String =
s"The exported type `$tpeName` in `$name` module will cause name conflict " +
s"when attempting to use a fully qualified name of the `$firstConflict` module."

View File

@ -2,6 +2,8 @@ package org.enso.compiler.core.ir
package expression
package warnings
import com.oracle.truffle.api.source.Source
/** Warnings for unreachable code. */
sealed trait Unreachable extends Warning {
val location: Option[IdentifiedLocation]
@ -23,7 +25,8 @@ object Unreachable {
""
}
override def message: String = s"Unreachable case branches$atLocation."
override def message(source: Source): String =
s"Unreachable case branches$atLocation."
override def diagnosticKeys(): Array[Any] = Array(atLocation)
}

View File

@ -2,6 +2,8 @@ package org.enso.compiler.core.ir
package expression
package warnings
import com.oracle.truffle.api.source.Source
/** Warnings about unused language entities. */
sealed trait Unused extends Warning {
val name: Name
@ -14,7 +16,8 @@ object Unused {
* @param name the name that is unused
*/
sealed case class FunctionArgument(override val name: Name) extends Unused {
override def message: String = s"Unused function argument ${name.name}."
override def message(source: Source): String =
s"Unused function argument ${name.name}."
override def diagnosticKeys(): Array[Any] = Array(name.name)
@ -24,7 +27,8 @@ object Unused {
}
sealed case class PatternBinding(override val name: Name) extends Unused {
override def message: String = s"Unused pattern binding ${name.name}."
override def message(source: Source): String =
s"Unused pattern binding ${name.name}."
override def diagnosticKeys(): Array[Any] = Array(name.name)
@ -38,7 +42,8 @@ object Unused {
* @param name the name that is unused
*/
sealed case class Binding(override val name: Name) extends Unused {
override def message: String = s"Unused variable ${name.name}."
override def message(source: Source): String =
s"Unused variable ${name.name}."
override def diagnosticKeys(): Array[Any] = Array(name.name)

View File

@ -1085,7 +1085,7 @@ class Compiler(
.Str(srcPath + ":" + lineNumber + ":" + startColumn + ": ")
.overlay(fansi.Bold.On)
str ++= fansi.Str(subject).overlay(textAttrs)
str ++= diagnostic.formattedMessage
str ++= diagnostic.formattedMessage(source)
str ++= "\n"
str ++= oneLineFromSourceColored(lineNumber, startColumn, endColumn)
str ++= "\n"
@ -1103,7 +1103,7 @@ class Compiler(
)
.overlay(fansi.Bold.On)
str ++= fansi.Str(subject).overlay(textAttrs)
str ++= diagnostic.formattedMessage
str ++= diagnostic.formattedMessage(source)
str ++= "\n"
val printAllSourceLines =
section.getEndLine - section.getStartLine <= maxSourceLinesToPrint
@ -1138,7 +1138,7 @@ class Compiler(
.overlay(fansi.Bold.On)
str ++= ": "
str ++= fansi.Str(subject).overlay(textAttrs)
str ++= diagnostic.formattedMessage
str ++= diagnostic.formattedMessage(source)
if (outSupportsAnsiColors) {
str.render.stripLineEnd
} else {

View File

@ -1738,43 +1738,43 @@ class IrToTruffle(
case err: errors.Syntax =>
context.getBuiltins
.error()
.makeSyntaxError(Text.create(err.message))
.makeSyntaxError(Text.create(err.message(source)))
case err: errors.Redefined.Binding =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Redefined.Method =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Redefined.MethodClashWithAtom =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Redefined.Conversion =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Redefined.Type =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Redefined.SelfArg =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Unexpected.TypeSignature =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Resolution =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case err: errors.Conversion =>
context.getBuiltins
.error()
.makeCompileError(Text.create(err.message))
.makeCompileError(Text.create(err.message(source)))
case _: errors.Pattern =>
throw new CompilerError(
"Impossible here, should be handled in the pattern match."

View File

@ -68,7 +68,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
imports = ir.imports.flatMap(imp => {
analyseAmbiguousSymbols(
imp,
moduleContext,
bindingMap,
encounteredSymbols
).fold(identity, imp => List(imp))
@ -86,7 +85,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
*/
private def analyseAmbiguousSymbols(
imp: Import,
module: ModuleContext,
bindingMap: BindingsMap,
encounteredSymbols: EncounteredSymbols
): Either[List[errors.ImportExport], Import] = {
@ -114,7 +112,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
case Right(resolvedName) =>
val symbolPath = resolvedName.qualifiedName.toString
tryAddEncounteredSymbol(
module,
encounteredSymbols,
imp,
symbolName,
@ -176,7 +173,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
)
case Right(resolvedName) =>
tryAddEncounteredSymbol(
module,
encounteredSymbols,
imp,
symbolName,
@ -213,7 +209,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
) =>
val symbolPath = importPath.name
tryAddEncounteredSymbol(
module,
encounteredSymbols,
moduleImport,
rename.name,
@ -236,7 +231,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
_
) =>
tryAddEncounteredSymbol(
module,
encounteredSymbols,
moduleImport,
importPath.parts.last.name,
@ -254,7 +248,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
packageName + "." + className
}
tryAddEncounteredSymbol(
module,
encounteredSymbols,
polyImport,
symbolName,
@ -284,7 +277,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
* in the map, checks whether the underlying entity path is the same as the original entity path.
* Based on that, either attaches a warning for a duplicated import, or returns an [[errors.ImportExport]].
*
* @param module Current module
* @param encounteredSymbols Encountered symbols in the current module
* @param currentImport Currently iterated import
* @param symbolName Name of the symbol that is about to be processed
@ -292,7 +284,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
* @return
*/
private def tryAddEncounteredSymbol(
module: ModuleContext,
encounteredSymbols: EncounteredSymbols,
currentImport: Import,
symbolName: String,
@ -306,7 +297,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
if (symbolPath == encounteredFullName) {
val warn =
createWarningForDuplicatedImport(
module,
originalImport,
currentImport,
symbolName
@ -315,7 +305,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
} else {
Left(
createErrorForAmbiguousImport(
module,
originalImport,
encounteredFullName,
currentImport,
@ -331,7 +320,6 @@ case object AmbiguousImportsAnalysis extends IRPass {
}
private def createErrorForAmbiguousImport(
module: ModuleContext,
originalImport: Import,
originalSymbolPath: String,
duplicatingImport: Import,
@ -344,14 +332,12 @@ case object AmbiguousImportsAnalysis extends IRPass {
originalImport,
originalSymbolPath,
ambiguousSymbol,
ambiguousSymbolPath,
module.getSource()
ambiguousSymbolPath
)
)
}
private def createWarningForDuplicatedImport(
module: ModuleContext,
originalImport: Import,
duplicatingImport: Import,
duplicatedSymbol: String
@ -359,8 +345,7 @@ case object AmbiguousImportsAnalysis extends IRPass {
Warning.DuplicatedImport(
duplicatingImport.location,
originalImport,
duplicatedSymbol,
module.getSource()
duplicatedSymbol
)
}

View File

@ -424,7 +424,7 @@ public class ErrorCompilerTest extends CompilerTest {
var errors = assertIR(ir, Syntax.class, 1);
assertEquals(type, errors.head().reason());
if (msg != null) {
assertEquals(msg, errors.head().message());
assertEquals(msg, errors.head().message(null));
}
assertEquals(new Location(start, end), errors.head().location().get().location());
}

View File

@ -132,7 +132,9 @@ class GatherDiagnosticsTest extends CompilerTest {
.unsafeGetMetadata(GatherDiagnostics, "Impossible")
.diagnostics
diagnostics should have size 2
diagnostics.map(_.message).toSet shouldEqual Set(
diagnostics
.map(_.message(null))
.toSet shouldEqual Set(
"Unused variable unused.",
"Unused function argument x."
)

View File

@ -14,7 +14,7 @@ import org.scalatest.BeforeAndAfter
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import java.io.ByteArrayOutputStream
import java.io.{ByteArrayOutputStream, ObjectOutputStream}
import java.nio.file.Paths
/** Tests a single package with multiple modules for import/export resolution.
@ -121,7 +121,8 @@ class ImportExportTest
mainIr.imports.head match {
case importErr: errors.ImportExport =>
fail(
s"Import should be resolved, but instead produced errors.ImportExport with ${importErr.reason.message}"
s"Import should be resolved, but instead produced errors.ImportExport with ${importErr.reason
.message(null)}"
)
case _ => ()
}
@ -884,6 +885,65 @@ class ImportExportTest
allWarns.foreach(_.symbolName shouldEqual "A_Type")
allWarns.foreach(_.originalImport shouldEqual origImport)
}
"serialize duplicated import warning" in {
s"""
|type A_Type
|""".stripMargin
.createModule(packageQualifiedName.createChild("A_Module"))
val mainIr =
s"""
|import $namespace.$packageName.A_Module.A_Type
|from $namespace.$packageName.A_Module import A_Type
|""".stripMargin
.createModule(packageQualifiedName.createChild("Main_Module"))
.getIr
mainIr.imports.size shouldEqual 2
val warn = mainIr
.imports(1)
.diagnostics
.collect({ case w: Warning.DuplicatedImport => w })
warn.size shouldEqual 1
val baos = new ByteArrayOutputStream()
val stream = new ObjectOutputStream(baos)
mainIr.preorder.foreach(
_.passData.prepareForSerialization(langCtx.getCompiler)
)
stream.writeObject(mainIr)
baos.toByteArray should not be empty
}
"serialize ambiguous import error" in {
s"""
|type A_Type
|""".stripMargin
.createModule(packageQualifiedName.createChild("A_Module"))
s"""
|type B_Type
|""".stripMargin
.createModule(packageQualifiedName.createChild("B_Module"))
val mainIr =
s"""
|from $namespace.$packageName.A_Module import A_Type
|import $namespace.$packageName.B_Module.B_Type as A_Type
|""".stripMargin
.createModule(packageQualifiedName.createChild("Main_Module"))
.getIr
mainIr.imports.size shouldEqual 2
val ambiguousImport = mainIr
.imports(1)
.asInstanceOf[errors.ImportExport]
.reason
.asInstanceOf[errors.ImportExport.AmbiguousImport]
ambiguousImport.symbolName shouldEqual "A_Type"
val baos = new ByteArrayOutputStream()
val stream = new ObjectOutputStream(baos)
mainIr.preorder.foreach(
_.passData.prepareForSerialization(langCtx.getCompiler)
)
stream.writeObject(mainIr)
baos.toByteArray should not be empty
}
}
"Import resolution for three modules" should {
@ -928,7 +988,8 @@ class ImportExportTest
mainIr.imports.head
.asInstanceOf[errors.ImportExport]
.reason
.message should include("A_Type")
.message(null) should include("A_Type")
}
"resolve all symbols (types and static module methods) from the module" in {