Skip to content

Commit 3ef4115

Browse files
committed
Merge pull request #1211 from dotty-staging/fix-#1202
Fix Tasty errors
2 parents 8af61ab + 7ea24c6 commit 3ef4115

23 files changed

+165
-80
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dotty.annotation.internal
2+
3+
import scala.annotation.Annotation
4+
5+
/** An annotation to record a Scala2 pickled alias.
6+
* @param aliased A TermRef pointing to the aliased field.
7+
*/
8+
class SourceFile(path: String) extends Annotation {
9+
10+
}

src/dotty/tools/dotc/FromTasty.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ object FromTasty extends Driver {
6464
}
6565

6666
class ReadTastyTreesFromClasses extends FrontEnd {
67+
68+
override def isTyper = false
69+
6770
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] =
6871
units.map(readTASTY)
6972

@@ -83,8 +86,8 @@ object FromTasty extends Driver {
8386
case info: ClassfileLoader =>
8487
info.load(clsd) match {
8588
case Some(unpickler: DottyUnpickler) =>
86-
val (List(unpickled), source) = unpickler.body(readPositions = true)
87-
val unit1 = new CompilationUnit(source)
89+
val List(unpickled) = unpickler.body(readPositions = true)
90+
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
8891
unit1.tpdTree = unpickled
8992
unit1.unpicklers += (clsd.classSymbol -> unpickler.unpickler)
9093
force.traverse(unit1.tpdTree)

src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ object Annotations {
9494
def makeChild(sym: Symbol)(implicit ctx: Context) =
9595
deferred(defn.ChildAnnot,
9696
implicit ctx => New(defn.ChildAnnotType.appliedTo(sym.owner.thisType.select(sym.name, sym)), Nil))
97+
98+
def makeSourceFile(path: String)(implicit ctx: Context) =
99+
apply(defn.SourceFileAnnot, Literal(Constant(path)))
97100
}
98101

99102
def ThrowsAnnotation(cls: ClassSymbol)(implicit ctx: Context) = {

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,13 +336,17 @@ object Contexts {
336336
def thisCallArgContext: Context = {
337337
assert(owner.isClassConstructor)
338338
val constrCtx = outersIterator.dropWhile(_.outer.owner == owner).next
339-
superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
339+
superOrThisCallContext(owner, constrCtx.scope)
340+
.setTyperState(typerState)
341+
.setGadt(gadt)
340342
}
341343

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

348352
/** The context of expression `expr` seen as a member of a statement sequence */
@@ -438,6 +442,7 @@ object Contexts {
438442
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
439443
def setRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
440444
def setDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
445+
def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
441446
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
442447
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
443448
def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }

src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ class Definitions {
456456
def RemoteAnnot(implicit ctx: Context) = RemoteAnnotType.symbol.asClass
457457
lazy val RepeatedAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Repeated")
458458
def RepeatedAnnot(implicit ctx: Context) = RepeatedAnnotType.symbol.asClass
459+
lazy val SourceFileAnnotType = ctx.requiredClassRef("dotty.annotation.internal.SourceFile")
460+
def SourceFileAnnot(implicit ctx: Context) = SourceFileAnnotType.symbol.asClass
459461
lazy val ScalaSignatureAnnotType = ctx.requiredClassRef("scala.reflect.ScalaSignature")
460462
def ScalaSignatureAnnot(implicit ctx: Context) = ScalaSignatureAnnotType.symbol.asClass
461463
lazy val ScalaLongSignatureAnnotType = ctx.requiredClassRef("scala.reflect.ScalaLongSignature")

src/dotty/tools/dotc/core/Phases.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,11 @@ object Phases {
291291
*/
292292
def relaxedTyping: Boolean = false
293293

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

297301
def exists: Boolean = true

src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import StdNames._
2121
import NameOps._
2222
import ast.tpd.Tree
2323
import ast.TreeTypeMap
24+
import Constants.Constant
2425
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
2526
import collection.mutable
2627
import io.AbstractFile
@@ -463,20 +464,23 @@ object Symbols {
463464
denot.topLevelClass.symbol.associatedFile
464465

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

469472
/** The source file from which this class was generated, null if not applicable. */
470-
final def sourceFile(implicit ctx: Context): AbstractFile =
471-
pickFile(associatedFile, classFile = false)
472-
473-
/** Desire to re-use the field in ClassSymbol which stores the source
474-
* file to also store the classfile, but without changing the behavior
475-
* of sourceFile (which is expected at least in the IDE only to
476-
* return actual source code.) So sourceFile has classfiles filtered out.
477-
*/
478-
private def pickFile(file: AbstractFile, classFile: Boolean): AbstractFile =
479-
if ((file eq null) || classFile != (file.path endsWith ".class")) null else file
473+
final def sourceFile(implicit ctx: Context): AbstractFile = {
474+
val file = associatedFile
475+
if (file != null && !file.path.endsWith("class")) file
476+
else denot.topLevelClass.getAnnotation(defn.SourceFileAnnot) match {
477+
case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match {
478+
case Some(Constant(path: String)) => AbstractFile.getFile(path)
479+
case none => null
480+
}
481+
case none => null
482+
}
483+
}
480484

481485
/** The position of this symbol, or NoPosition is symbol was not loaded
482486
* from source.

src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,20 @@ package dotc
33
package core
44
package tasty
55

6-
import Contexts._, SymDenotations._
6+
import Contexts._, SymDenotations._, Symbols._
77
import dotty.tools.dotc.ast.tpd
88
import TastyUnpickler._, TastyBuffer._
9-
import dotty.tools.dotc.core.tasty.DottyUnpickler.{SourceFileUnpickler, TreeSectionUnpickler, PositionsSectionUnpickler}
109
import util.Positions._
1110
import util.{SourceFile, NoSource}
1211
import PositionUnpickler._
12+
import Annotations.Annotation
1313
import classfile.ClassfileParser
1414

1515
object DottyUnpickler {
1616

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

20-
class SourceFileUnpickler extends SectionUnpickler[SourceFile]("Sourcefile") {
21-
def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
22-
new SourceFile(tastyName(reader.readNameRef()).toString, Seq())
23-
}
24-
2520
class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") {
2621
def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
2722
new TreeUnpickler(reader, tastyName)
@@ -38,6 +33,7 @@ object DottyUnpickler {
3833
*/
3934
class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
4035
import tpd._
36+
import DottyUnpickler._
4137

4238
val unpickler = new TastyUnpickler(bytes)
4339
private val treeUnpickler = unpickler.unpickle(new TreeSectionUnpickler).get
@@ -51,11 +47,10 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
5147
/** The unpickled trees, and the source file they come from
5248
* @param readPositions if true, trees get decorated with position information.
5349
*/
54-
def body(readPositions: Boolean = false)(implicit ctx: Context): (List[Tree], SourceFile) = {
55-
val source = unpickler.unpickle(new SourceFileUnpickler).getOrElse(NoSource)
50+
def body(readPositions: Boolean = false)(implicit ctx: Context): List[Tree] = {
5651
if (readPositions)
5752
for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler))
5853
treeUnpickler.usePositions(totalRange, positions)
59-
(treeUnpickler.unpickle(), source)
54+
treeUnpickler.unpickle()
6055
}
6156
}

src/dotty/tools/dotc/core/tasty/TastyFormat.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Standard-Section: "ASTs" TopLevelStat*
8484
MATCH Length sel_Term CaseDef*
8585
TRY Length expr_Term CaseDef* finalizer_Term?
8686
RETURN Length meth_ASTRef expr_Term?
87-
REPEATED Length elem_Term*
87+
REPEATED Length elem_Type elem_Term*
8888
BIND Length boundName_NameRef patType_Type pat_Term
8989
ALTERNATIVE Length alt_Term*
9090
UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term*
@@ -184,8 +184,6 @@ Note: Tree tags are grouped into 5 categories that determine what follows, and t
184184
Category 4 (tags 112-127): tag Nat AST
185185
Category 5 (tags 128-255): tag Length <payload>
186186
187-
Standard Section: "Sourcefile" sourcefile_NameRef
188-
189187
Standard Section: "Positions" sourceLength_Nat Assoc*
190188
191189
Assoc = addr_Delta offset_Delta offset_Delta?

src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
596596
vparamss.nestedMap(_.symbol), name == nme.CONSTRUCTOR)
597597
val resType = ctx.effectiveResultType(sym, typeParams, tpt.tpe)
598598
sym.info = ctx.methodType(typeParams, valueParamss, resType)
599+
if (sym.isSetter && sym.accessedFieldOrGetter.is(ParamAccessor)) {
600+
// reconstitute ParamAccessor flag of setters for var parameters, which is not pickled
601+
sym.setFlag(ParamAccessor)
602+
sym.resetFlag(Deferred)
603+
}
599604
DefDef(tparams, vparamss, tpt)
600605
case VALDEF =>
601606
sym.info = readType()
@@ -802,9 +807,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
802807
tpd.Super(qual, mixName, ctx.mode.is(Mode.InSuperCall), mixClass)
803808
case APPLY =>
804809
val fn = readTerm()
805-
val isJava = fn.tpe.isInstanceOf[JavaMethodType]
810+
val isJava = fn.symbol.is(JavaDefined)
806811
def readArg() = readTerm() match {
807-
case SeqLiteral(elems, elemtpt) if isJava => JavaSeqLiteral(elems, elemtpt)
812+
case SeqLiteral(elems, elemtpt) if isJava =>
813+
JavaSeqLiteral(elems, elemtpt)
808814
case arg => arg
809815
}
810816
tpd.Apply(fn, until(end)(readArg()))
@@ -813,7 +819,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
813819
case PAIR =>
814820
Pair(readTerm(), readTerm())
815821
case TYPED =>
816-
Typed(readTerm(), readTpt())
822+
val expr = readTerm()
823+
val tpt = readTpt()
824+
val expr1 = expr match {
825+
case SeqLiteral(elems, elemtpt) if tpt.tpe.isRef(defn.ArrayClass) =>
826+
JavaSeqLiteral(elems, elemtpt)
827+
case expr => expr
828+
}
829+
Typed(expr1, tpt)
817830
case NAMEDARG =>
818831
NamedArg(readName(), readTerm())
819832
case ASSIGN =>

src/dotty/tools/dotc/transform/ExpandPrivate.scala

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import TreeTransforms._
1616
import Decorators._
1717
import ast.Trees._
1818
import TreeTransforms._
19+
import java.io.File.separatorChar
1920

2021
/** Make private term members that are accessed from another class
2122
* non-private by resetting the Private flag and expanding their name.
@@ -58,7 +59,20 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
5859
*/
5960
private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) =
6061
if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
61-
assert(d.symbol.sourceFile == ctx.source.file,
62+
// Paths `p1` and `p2` are similar if they have a common suffix that follows
63+
// possibly different directory paths. That is, their common suffix extends
64+
// in both cases either to the start of the path or to a file separator character.
65+
def isSimilar(p1: String, p2: String): Boolean = {
66+
var i = p1.length - 1
67+
var j = p2.length - 1
68+
while (i >= 0 && j >= 0 && p1(i) == p2(j) && p1(i) != separatorChar) {
69+
i -= 1
70+
j -= 1
71+
}
72+
(i < 0 || p1(i) == separatorChar) &&
73+
(j < 0 || p1(j) == separatorChar)
74+
}
75+
assert(isSimilar(d.symbol.sourceFile.path, ctx.source.file.path),
6276
i"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.source.file}")
6377
d.ensureNotPrivate.installAfter(thisTransform)
6478
}

src/dotty/tools/dotc/transform/Pickler.scala

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import Periods._
1111
import Phases._
1212
import Symbols._
1313
import Flags.Module
14-
import util.SourceFile
1514
import collection.mutable
1615

1716
/** This phase pickles trees */
@@ -48,8 +47,6 @@ class Pickler extends Phase {
4847
treePkl.pickle(tree :: Nil)
4948
pickler.addrOfTree = treePkl.buf.addrOfTree
5049
pickler.addrOfSym = treePkl.addrOfSym
51-
if (unit.source.exists)
52-
pickleSourcefile(pickler, unit.source)
5350
if (tree.pos.exists)
5451
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
5552

@@ -65,12 +62,6 @@ class Pickler extends Phase {
6562
}
6663
}
6764

68-
private def pickleSourcefile(pickler: TastyPickler, source: SourceFile): Unit = {
69-
val buf = new TastyBuffer(10)
70-
pickler.newSection("Sourcefile", buf)
71-
buf.writeNat(pickler.nameBuffer.nameIndex(source.file.path).index)
72-
}
73-
7465
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
7566
val result = super.runOn(units)
7667
if (ctx.settings.YtestPickler.value)
@@ -89,16 +80,16 @@ class Pickler extends Phase {
8980
}
9081
pickling.println("************* entered toplevel ***********")
9182
for ((cls, unpickler) <- unpicklers) {
92-
val (unpickled, source) = unpickler.body(readPositions = true)
93-
testSame(i"$unpickled%\n%", beforePickling(cls), cls, source)
83+
val unpickled = unpickler.body(readPositions = true)
84+
testSame(i"$unpickled%\n%", beforePickling(cls), cls)
9485
}
9586
}
9687

97-
private def testSame(unpickled: String, previous: String, cls: ClassSymbol, source: SourceFile)(implicit ctx: Context) =
88+
private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(implicit ctx: Context) =
9889
if (previous != unpickled) {
9990
output("before-pickling.txt", previous)
10091
output("after-pickling.txt", unpickled)
101-
ctx.error(s"""pickling difference for ${cls.fullName} in $source, for details:
92+
ctx.error(s"""pickling difference for ${cls.fullName} in ${cls.sourceFile}, for details:
10293
|
10394
| diff before-pickling.txt after-pickling.txt""".stripMargin)
10495
}

src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import Symbols._, TypeUtils._
3636
*
3737
* (8) Replaces self references by name with `this`
3838
*
39+
* (9) Adds SourceFile annotations to all top-level classes and objects
40+
*
3941
* The reason for making this a macro transform is that some functions (in particular
4042
* super and protected accessors and instantiation checks) are naturally top-down and
4143
* don't lend themselves to the bottom-up approach of a mini phase. The other two functions
@@ -224,7 +226,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
224226
transformMemberDef(tree)
225227
val sym = tree.symbol
226228
val tree1 =
227-
if (sym.isClass) tree
229+
if (sym.isClass) {
230+
if (sym.owner.is(Package) &&
231+
ctx.compilationUnit.source.exists &&
232+
sym != defn.SourceFileAnnot)
233+
sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))
234+
tree
235+
}
228236
else {
229237
Checking.typeChecker.traverse(tree.rhs)
230238
cpy.TypeDef(tree)(rhs = TypeTree(tree.symbol.info))

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -531,12 +531,16 @@ trait Applications extends Compatibility { self: Typer =>
531531
def treeToArg(arg: Tree): Tree = arg
532532
}
533533

534+
/** If `app` is a `this(...)` constructor call, the this-call argument context,
535+
* otherwise the current context.
536+
*/
537+
def argCtx(app: untpd.Tree)(implicit ctx: Context): Context =
538+
if (untpd.isSelfConstrCall(app)) ctx.thisCallArgContext else ctx
539+
534540
def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
535541

536542
def realApply(implicit ctx: Context): Tree = track("realApply") {
537-
def argCtx(implicit ctx: Context) =
538-
if (untpd.isSelfConstrCall(tree)) ctx.thisCallArgContext else ctx
539-
var proto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx)
543+
var proto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx(tree))
540544
val fun1 = typedExpr(tree.fun, proto)
541545

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

0 commit comments

Comments
 (0)