Skip to content

Fix Tasty errors #1211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Apr 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
422b061
Search implicit arguments in the same context as typing explicit ones
odersky Apr 7, 2016
306d422
Take type parameters for this(...) constructor calls from prefix
odersky Apr 7, 2016
03e8c54
Treat type parameters of secondary constructors as aliases
odersky Apr 7, 2016
e2cdfa3
Augment test case
odersky Apr 7, 2016
90f9653
Make first phase of FromTasty not be a Typer
odersky Apr 7, 2016
3e0be57
Add dotty.annotation.internal.SourceFile annotation
odersky Apr 7, 2016
b3b3f3c
Fix reading of SourceFile attribute from Tasty
odersky Apr 7, 2016
cb1f386
Pickle sourcefile attribute with canonical path
odersky Apr 7, 2016
8ddfa83
Add unpickled source file path as annotation to root symbols
odersky Apr 7, 2016
cc7acea
Take SourceFile annotations into account when computing sourceFile
odersky Apr 7, 2016
29e5792
Test cases
odersky Apr 7, 2016
88eb98f
Fix flags when unpickling setters of parameter accessors
odersky Apr 7, 2016
56b948c
Update TastyFormat for SeqLiteral
odersky Apr 7, 2016
20175a0
Fix unpickling of Java SeqLiterals
odersky Apr 7, 2016
b37a2a8
Add source file for SourceFile annotation
odersky Apr 8, 2016
5debb09
Explain isTyper field in Phase.
odersky Apr 8, 2016
f9d27c9
Store source files as normal paths, not canonical ones.
odersky Apr 8, 2016
5aa59ac
Simplify handling of sourcefiles in Tasty info
odersky Apr 9, 2016
0907f5b
Avoid creating a SourceFile annotation for SourceFile itself
odersky Apr 9, 2016
6942127
Rearrange pickle tests
odersky Apr 9, 2016
7ea24c6
Update TASTY tests for dotty/src
VladimirNik Apr 13, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/dotty/annotation/internal/SourceFile.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dotty.annotation.internal

import scala.annotation.Annotation

/** An annotation to record a Scala2 pickled alias.
* @param aliased A TermRef pointing to the aliased field.
*/
class SourceFile(path: String) extends Annotation {

}
7 changes: 5 additions & 2 deletions src/dotty/tools/dotc/FromTasty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ object FromTasty extends Driver {
}

class ReadTastyTreesFromClasses extends FrontEnd {

override def isTyper = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this is not enough.
A lot of code checks for Phases.isAfterTyper that is entirely independent from this method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. But it does not matter for anyway. The change did not affect the fixes. I'll add a comment to explain better what isTyper is.


override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] =
units.map(readTASTY)

Expand All @@ -83,8 +86,8 @@ object FromTasty extends Driver {
case info: ClassfileLoader =>
info.load(clsd) match {
case Some(unpickler: DottyUnpickler) =>
val (List(unpickled), source) = unpickler.body(readPositions = true)
val unit1 = new CompilationUnit(source)
val List(unpickled) = unpickler.body(readPositions = true)
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
unit1.tpdTree = unpickled
unit1.unpicklers += (clsd.classSymbol -> unpickler.unpickler)
force.traverse(unit1.tpdTree)
Expand Down
3 changes: 3 additions & 0 deletions src/dotty/tools/dotc/core/Annotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ object Annotations {
def makeChild(sym: Symbol)(implicit ctx: Context) =
deferred(defn.ChildAnnot,
implicit ctx => New(defn.ChildAnnotType.appliedTo(sym.owner.thisType.select(sym.name, sym)), Nil))

def makeSourceFile(path: String)(implicit ctx: Context) =
apply(defn.SourceFileAnnot, Literal(Constant(path)))
}

def ThrowsAnnotation(cls: ClassSymbol)(implicit ctx: Context) = {
Expand Down
11 changes: 8 additions & 3 deletions src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -336,13 +336,17 @@ object Contexts {
def thisCallArgContext: Context = {
assert(owner.isClassConstructor)
val constrCtx = outersIterator.dropWhile(_.outer.owner == owner).next
superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
superOrThisCallContext(owner, constrCtx.scope)
.setTyperState(typerState)
.setGadt(gadt)
}

/** The super= or this-call context with given owner and locals. */
/** The super- or this-call context with given owner and locals. */
private def superOrThisCallContext(owner: Symbol, locals: Scope): FreshContext = {
var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
classCtx.outer.fresh.setOwner(owner).setScope(locals).setMode(classCtx.mode | Mode.InSuperCall)
classCtx.outer.fresh.setOwner(owner)
.setScope(locals)
.setMode(classCtx.mode | Mode.InSuperCall)
}

/** The context of expression `expr` seen as a member of a statement sequence */
Expand Down Expand Up @@ -438,6 +442,7 @@ object Contexts {
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
def setRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
def setDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }
Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ class Definitions {
def RemoteAnnot(implicit ctx: Context) = RemoteAnnotType.symbol.asClass
lazy val RepeatedAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Repeated")
def RepeatedAnnot(implicit ctx: Context) = RepeatedAnnotType.symbol.asClass
lazy val SourceFileAnnotType = ctx.requiredClassRef("dotty.annotation.internal.SourceFile")
def SourceFileAnnot(implicit ctx: Context) = SourceFileAnnotType.symbol.asClass
lazy val ScalaSignatureAnnotType = ctx.requiredClassRef("scala.reflect.ScalaSignature")
def ScalaSignatureAnnot(implicit ctx: Context) = ScalaSignatureAnnotType.symbol.asClass
lazy val ScalaLongSignatureAnnotType = ctx.requiredClassRef("scala.reflect.ScalaLongSignature")
Expand Down
6 changes: 5 additions & 1 deletion src/dotty/tools/dotc/core/Phases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,11 @@ object Phases {
*/
def relaxedTyping: Boolean = false

/** Overridden by FrontEnd */
/** Is this phase the standard typerphase? True for FrontEnd, but
* not for other first phases (such as FromTasty). The predicate
* is tested in some places that perform checks and corrections. It's
* different from isAfterTyper (and cheaper to test).
*/
def isTyper = false

def exists: Boolean = true
Expand Down
28 changes: 16 additions & 12 deletions src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import StdNames._
import NameOps._
import ast.tpd.Tree
import ast.TreeTypeMap
import Constants.Constant
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
import io.AbstractFile
Expand Down Expand Up @@ -463,20 +464,23 @@ object Symbols {
denot.topLevelClass.symbol.associatedFile

/** The class file from which this class was generated, null if not applicable. */
final def binaryFile(implicit ctx: Context): AbstractFile =
pickFile(associatedFile, classFile = true)
final def binaryFile(implicit ctx: Context): AbstractFile = {
val file = associatedFile
if (file != null && file.path.endsWith("class")) file else null
}

/** The source file from which this class was generated, null if not applicable. */
final def sourceFile(implicit ctx: Context): AbstractFile =
pickFile(associatedFile, classFile = false)

/** Desire to re-use the field in ClassSymbol which stores the source
* file to also store the classfile, but without changing the behavior
* of sourceFile (which is expected at least in the IDE only to
* return actual source code.) So sourceFile has classfiles filtered out.
*/
private def pickFile(file: AbstractFile, classFile: Boolean): AbstractFile =
if ((file eq null) || classFile != (file.path endsWith ".class")) null else file
final def sourceFile(implicit ctx: Context): AbstractFile = {
val file = associatedFile
if (file != null && !file.path.endsWith("class")) file
else denot.topLevelClass.getAnnotation(defn.SourceFileAnnot) match {
case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match {
case Some(Constant(path: String)) => AbstractFile.getFile(path)
case none => null
}
case none => null
}
}

/** The position of this symbol, or NoPosition is symbol was not loaded
* from source.
Expand Down
15 changes: 5 additions & 10 deletions src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,20 @@ package dotc
package core
package tasty

import Contexts._, SymDenotations._
import Contexts._, SymDenotations._, Symbols._
import dotty.tools.dotc.ast.tpd
import TastyUnpickler._, TastyBuffer._
import dotty.tools.dotc.core.tasty.DottyUnpickler.{SourceFileUnpickler, TreeSectionUnpickler, PositionsSectionUnpickler}
import util.Positions._
import util.{SourceFile, NoSource}
import PositionUnpickler._
import Annotations.Annotation
import classfile.ClassfileParser

object DottyUnpickler {

/** Exception thrown if classfile is corrupted */
class BadSignature(msg: String) extends RuntimeException(msg)

class SourceFileUnpickler extends SectionUnpickler[SourceFile]("Sourcefile") {
def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
new SourceFile(tastyName(reader.readNameRef()).toString, Seq())
}

class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") {
def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
new TreeUnpickler(reader, tastyName)
Expand All @@ -38,6 +33,7 @@ object DottyUnpickler {
*/
class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
import tpd._
import DottyUnpickler._

val unpickler = new TastyUnpickler(bytes)
private val treeUnpickler = unpickler.unpickle(new TreeSectionUnpickler).get
Expand All @@ -51,11 +47,10 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
/** The unpickled trees, and the source file they come from
* @param readPositions if true, trees get decorated with position information.
*/
def body(readPositions: Boolean = false)(implicit ctx: Context): (List[Tree], SourceFile) = {
val source = unpickler.unpickle(new SourceFileUnpickler).getOrElse(NoSource)
def body(readPositions: Boolean = false)(implicit ctx: Context): List[Tree] = {
if (readPositions)
for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler))
treeUnpickler.usePositions(totalRange, positions)
(treeUnpickler.unpickle(), source)
treeUnpickler.unpickle()
}
}
4 changes: 1 addition & 3 deletions src/dotty/tools/dotc/core/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Standard-Section: "ASTs" TopLevelStat*
MATCH Length sel_Term CaseDef*
TRY Length expr_Term CaseDef* finalizer_Term?
RETURN Length meth_ASTRef expr_Term?
REPEATED Length elem_Term*
REPEATED Length elem_Type elem_Term*
BIND Length boundName_NameRef patType_Type pat_Term
ALTERNATIVE Length alt_Term*
UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term*
Expand Down Expand Up @@ -184,8 +184,6 @@ Note: Tree tags are grouped into 5 categories that determine what follows, and t
Category 4 (tags 112-127): tag Nat AST
Category 5 (tags 128-255): tag Length <payload>

Standard Section: "Sourcefile" sourcefile_NameRef

Standard Section: "Positions" sourceLength_Nat Assoc*

Assoc = addr_Delta offset_Delta offset_Delta?
Expand Down
19 changes: 16 additions & 3 deletions src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
vparamss.nestedMap(_.symbol), name == nme.CONSTRUCTOR)
val resType = ctx.effectiveResultType(sym, typeParams, tpt.tpe)
sym.info = ctx.methodType(typeParams, valueParamss, resType)
if (sym.isSetter && sym.accessedFieldOrGetter.is(ParamAccessor)) {
// reconstitute ParamAccessor flag of setters for var parameters, which is not pickled
sym.setFlag(ParamAccessor)
sym.resetFlag(Deferred)
}
DefDef(tparams, vparamss, tpt)
case VALDEF =>
sym.info = readType()
Expand Down Expand Up @@ -802,9 +807,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
tpd.Super(qual, mixName, ctx.mode.is(Mode.InSuperCall), mixClass)
case APPLY =>
val fn = readTerm()
val isJava = fn.tpe.isInstanceOf[JavaMethodType]
val isJava = fn.symbol.is(JavaDefined)
def readArg() = readTerm() match {
case SeqLiteral(elems, elemtpt) if isJava => JavaSeqLiteral(elems, elemtpt)
case SeqLiteral(elems, elemtpt) if isJava =>
JavaSeqLiteral(elems, elemtpt)
case arg => arg
}
tpd.Apply(fn, until(end)(readArg()))
Expand All @@ -813,7 +819,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
case PAIR =>
Pair(readTerm(), readTerm())
case TYPED =>
Typed(readTerm(), readTpt())
val expr = readTerm()
val tpt = readTpt()
val expr1 = expr match {
case SeqLiteral(elems, elemtpt) if tpt.tpe.isRef(defn.ArrayClass) =>
JavaSeqLiteral(elems, elemtpt)
case expr => expr
}
Typed(expr1, tpt)
case NAMEDARG =>
NamedArg(readName(), readTerm())
case ASSIGN =>
Expand Down
16 changes: 15 additions & 1 deletion src/dotty/tools/dotc/transform/ExpandPrivate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import TreeTransforms._
import Decorators._
import ast.Trees._
import TreeTransforms._
import java.io.File.separatorChar

/** Make private term members that are accessed from another class
* non-private by resetting the Private flag and expanding their name.
Expand Down Expand Up @@ -58,7 +59,20 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
*/
private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) =
if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
assert(d.symbol.sourceFile == ctx.source.file,
// Paths `p1` and `p2` are similar if they have a common suffix that follows
// possibly different directory paths. That is, their common suffix extends
// in both cases either to the start of the path or to a file separator character.
def isSimilar(p1: String, p2: String): Boolean = {
var i = p1.length - 1
var j = p2.length - 1
while (i >= 0 && j >= 0 && p1(i) == p2(j) && p1(i) != separatorChar) {
i -= 1
j -= 1
}
(i < 0 || p1(i) == separatorChar) &&
(j < 0 || p1(j) == separatorChar)
}
assert(isSimilar(d.symbol.sourceFile.path, ctx.source.file.path),
i"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.source.file}")
d.ensureNotPrivate.installAfter(thisTransform)
}
Expand Down
17 changes: 4 additions & 13 deletions src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Periods._
import Phases._
import Symbols._
import Flags.Module
import util.SourceFile
import collection.mutable

/** This phase pickles trees */
Expand Down Expand Up @@ -48,8 +47,6 @@ class Pickler extends Phase {
treePkl.pickle(tree :: Nil)
pickler.addrOfTree = treePkl.buf.addrOfTree
pickler.addrOfSym = treePkl.addrOfSym
if (unit.source.exists)
pickleSourcefile(pickler, unit.source)
if (tree.pos.exists)
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)

Expand All @@ -65,12 +62,6 @@ class Pickler extends Phase {
}
}

private def pickleSourcefile(pickler: TastyPickler, source: SourceFile): Unit = {
val buf = new TastyBuffer(10)
pickler.newSection("Sourcefile", buf)
buf.writeNat(pickler.nameBuffer.nameIndex(source.file.path).index)
}

override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
val result = super.runOn(units)
if (ctx.settings.YtestPickler.value)
Expand All @@ -89,16 +80,16 @@ class Pickler extends Phase {
}
pickling.println("************* entered toplevel ***********")
for ((cls, unpickler) <- unpicklers) {
val (unpickled, source) = unpickler.body(readPositions = true)
testSame(i"$unpickled%\n%", beforePickling(cls), cls, source)
val unpickled = unpickler.body(readPositions = true)
testSame(i"$unpickled%\n%", beforePickling(cls), cls)
}
}

private def testSame(unpickled: String, previous: String, cls: ClassSymbol, source: SourceFile)(implicit ctx: Context) =
private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(implicit ctx: Context) =
if (previous != unpickled) {
output("before-pickling.txt", previous)
output("after-pickling.txt", unpickled)
ctx.error(s"""pickling difference for ${cls.fullName} in $source, for details:
ctx.error(s"""pickling difference for ${cls.fullName} in ${cls.sourceFile}, for details:
|
| diff before-pickling.txt after-pickling.txt""".stripMargin)
}
Expand Down
10 changes: 9 additions & 1 deletion src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import Symbols._, TypeUtils._
*
* (8) Replaces self references by name with `this`
*
* (9) Adds SourceFile annotations to all top-level classes and objects
*
* The reason for making this a macro transform is that some functions (in particular
* super and protected accessors and instantiation checks) are naturally top-down and
* don't lend themselves to the bottom-up approach of a mini phase. The other two functions
Expand Down Expand Up @@ -224,7 +226,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
transformMemberDef(tree)
val sym = tree.symbol
val tree1 =
if (sym.isClass) tree
if (sym.isClass) {
if (sym.owner.is(Package) &&
ctx.compilationUnit.source.exists &&
sym != defn.SourceFileAnnot)
sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))
tree
}
else {
Checking.typeChecker.traverse(tree.rhs)
cpy.TypeDef(tree)(rhs = TypeTree(tree.symbol.info))
Expand Down
12 changes: 8 additions & 4 deletions src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -531,12 +531,16 @@ trait Applications extends Compatibility { self: Typer =>
def treeToArg(arg: Tree): Tree = arg
}

/** If `app` is a `this(...)` constructor call, the this-call argument context,
* otherwise the current context.
*/
def argCtx(app: untpd.Tree)(implicit ctx: Context): Context =
if (untpd.isSelfConstrCall(app)) ctx.thisCallArgContext else ctx

def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {

def realApply(implicit ctx: Context): Tree = track("realApply") {
def argCtx(implicit ctx: Context) =
if (untpd.isSelfConstrCall(tree)) ctx.thisCallArgContext else ctx
var proto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx)
var proto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx(tree))
val fun1 = typedExpr(tree.fun, proto)

// Warning: The following line is dirty and fragile. We record that auto-tupling was demanded as
Expand All @@ -554,7 +558,7 @@ trait Applications extends Compatibility { self: Typer =>
tryEither { implicit ctx =>
val app =
if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
else new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx)
else new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree))
val result = app.result
convertNewArray(ConstFold(result))
} { (failedVal, failedState) =>
Expand Down
Loading