Skip to content

Commit 79e0fe0

Browse files
authored
Merge pull request #1289 from dotty-staging/fix/partest-separate
partest: Enable separate compilation
2 parents 48d6460 + 04e6d5e commit 79e0fe0

File tree

17 files changed

+96
-39
lines changed

17 files changed

+96
-39
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2645,6 +2645,9 @@ object Types {
26452645
if (ctx.period != validSuper) {
26462646
cachedSuper = tycon match {
26472647
case tp: TypeLambda => defn.AnyType
2648+
case tp: TypeVar if !tp.inst.exists =>
2649+
// supertype not stable, since underlying might change
2650+
return tp.underlying.applyIfParameterized(args)
26482651
case tp: TypeProxy => tp.superType.applyIfParameterized(args)
26492652
case _ => defn.AnyType
26502653
}

src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,6 @@ class ClassfileParser(
580580
* parameters. For Java annotations we need to fake it by making up the constructor.
581581
* Note that default getters have type Nothing. That's OK because we need
582582
* them only to signal that the corresponding parameter is optional.
583-
* If the constructor takes as last parameter an array, it can also accept
584-
* a vararg argument. We solve this by creating two constructors, one with
585-
* an array, the other with a repeated parameter.
586583
*/
587584
def addAnnotationConstructor(classInfo: Type, tparams: List[TypeSymbol] = Nil)(implicit ctx: Context): Unit = {
588585
def addDefaultGetter(attr: Symbol, n: Int) =
@@ -618,13 +615,26 @@ class ClassfileParser(
618615
}
619616

620617
addConstr(paramTypes)
618+
619+
// The code below added an extra constructor to annotations where the
620+
// last parameter of the constructor is an Array[X] for some X, the
621+
// array was replaced by a vararg argument. Unfortunately this breaks
622+
// inference when doing:
623+
// @Annot(Array())
624+
// The constructor is overloaded so the expected type of `Array()` is
625+
// WildcardType, and the type parameter of the Array apply method gets
626+
// instantiated to `Nothing` instead of `X`.
627+
// I'm leaving this commented out in case we improve inference to make this work.
628+
// Note that if this is reenabled then JavaParser will also need to be modified
629+
// to add the extra constructor (this was not implemented before).
630+
/*
621631
if (paramTypes.nonEmpty)
622632
paramTypes.last match {
623633
case defn.ArrayOf(elemtp) =>
624634
addConstr(paramTypes.init :+ defn.RepeatedParamType.appliedTo(elemtp))
625635
case _ =>
626636
}
627-
637+
*/
628638
}
629639
}
630640

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@ import Decorators._
1717
import ast.Trees._
1818
import TreeTransforms._
1919
import java.io.File.separatorChar
20+
import ValueClasses._
2021

2122
/** Make private term members that are accessed from another class
2223
* non-private by resetting the Private flag and expanding their name.
2324
*
25+
* Make private accessor in value class not-private. Ihis is necessary to unbox
26+
* the value class when accessing it from separate compilation units
27+
*
2428
* Also, make non-private any private parameter forwarders that forward to an inherited
2529
* public or protected parameter accessor with the same name as the forwarder.
2630
* This is necessary since private methods are not allowed to have the same name
@@ -52,13 +56,18 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
5256
}
5357
}
5458

59+
private def isVCPrivateParamAccessor(d: SymDenotation)(implicit ctx: Context) =
60+
d.isTerm && d.is(PrivateParamAccessor) && isDerivedValueClass(d.owner)
61+
5562
/** Make private terms accessed from different classes non-private.
5663
* Note: this happens also for accesses between class and linked module class.
5764
* If we change the scheme at one point to make static module class computations
5865
* static members of the companion class, we should tighten the condition below.
5966
*/
6067
private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) =
61-
if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
68+
if (isVCPrivateParamAccessor(d))
69+
d.ensureNotPrivate.installAfter(thisTransform)
70+
else if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
6271
// Paths `p1` and `p2` are similar if they have a common suffix that follows
6372
// possibly different directory paths. That is, their common suffix extends
6473
// in both cases either to the start of the path or to a file separator character.
@@ -94,6 +103,8 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
94103
if sym.is(PrivateParamAccessor) && sel.symbol.is(ParamAccessor) && sym.name == sel.symbol.name =>
95104
sym.ensureNotPrivate.installAfter(thisTransform)
96105
case _ =>
106+
if (isVCPrivateParamAccessor(sym))
107+
sym.ensureNotPrivate.installAfter(thisTransform)
97108
}
98109
tree
99110
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf
4747

4848
/** Add outer accessors if a class always needs an outer pointer */
4949
override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context) = tp match {
50-
case tp @ ClassInfo(_, cls, _, decls, _) if needsOuterAlways(cls) =>
50+
case tp @ ClassInfo(_, cls, _, decls, _) if needsOuterAlways(cls) && !sym.is(JavaDefined) =>
5151
val newDecls = decls.cloneScope
5252
newOuterAccessors(cls).foreach(newDecls.enter)
5353
tp.derivedClassInfo(decls = newDecls)

src/strawman/collections/CollectionStrawMan4.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ object CollectionStrawMan4 {
218218
def fromIterable[B](coll: Iterable[B]): ListBuffer[B] = coll match {
219219
case pd @ View.Partitioned(partition: View.Partition[B]) =>
220220
partition.distribute(new ListBuffer[B]())
221-
pd.forced.get.asInstanceOf[ListBuffer[B]]
221+
new ListBuffer[B] ++= pd.forced.get
222222
case _ =>
223223
new ListBuffer[B] ++= coll
224224
}

test/dotty/partest/DPConsoleRunner.scala

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,62 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn
134134
// override to provide DottyCompiler
135135
override def newCompiler = new dotty.partest.DPDirectCompiler(this)
136136

137+
// Adapted from nest.Runner#javac because:
138+
// - Our classpath handling is different and we need to pass extraClassPath
139+
// to java to get the scala-library which is required for some java tests
140+
// - The compiler output should be redirected to cLogFile, like the output of
141+
// dotty itself
142+
override def javac(files: List[File]): TestState = {
143+
import fileManager._
144+
import suiteRunner._
145+
import FileManager.joinPaths
146+
// compile using command-line javac compiler
147+
val args = Seq(
148+
javacCmdPath,
149+
"-d",
150+
outDir.getAbsolutePath,
151+
"-classpath",
152+
joinPaths(outDir :: extraClasspath ++ testClassPath)
153+
) ++ files.map(_.getAbsolutePath)
154+
155+
pushTranscript(args mkString " ")
156+
157+
val captured = StreamCapture(runCommand(args, cLogFile))
158+
if (captured.result) genPass() else {
159+
cLogFile appendAll captured.stderr
160+
cLogFile appendAll captured.stdout
161+
genFail("java compilation failed")
162+
}
163+
}
164+
165+
// FIXME: This is copy-pasted from nest.Runner where it is private
166+
// Remove this once https://github.com/scala/scala-partest/pull/61 is merged
167+
/** Runs command redirecting standard out and
168+
* error out to output file.
169+
*/
170+
def runCommand(args: Seq[String], outFile: File): Boolean = {
171+
import scala.sys.process.{ Process, ProcessLogger }
172+
//(Process(args) #> outFile !) == 0 or (Process(args) ! pl) == 0
173+
val pl = ProcessLogger(outFile)
174+
val nonzero = 17 // rounding down from 17.3
175+
def run: Int = {
176+
val p = Process(args) run pl
177+
try p.exitValue
178+
catch {
179+
case e: InterruptedException =>
180+
NestUI verbose s"Interrupted waiting for command to finish (${args mkString " "})"
181+
p.destroy
182+
nonzero
183+
case t: Throwable =>
184+
NestUI verbose s"Exception waiting for command to finish: $t (${args mkString " "})"
185+
p.destroy
186+
throw t
187+
}
188+
finally pl.close()
189+
}
190+
(pl buffer run) == 0
191+
}
192+
137193
// override to provide default dotty flags from file in directory
138194
override def flagsForCompilation(sources: List[File]): List[String] = {
139195
val specificFlags = super.flagsForCompilation(sources)
@@ -245,32 +301,6 @@ class DPTestRunner(testFile: File, suiteRunner: DPSuiteRunner) extends nest.Runn
245301
} getOrElse true
246302
}
247303

248-
// override because Dotty currently doesn't handle separate compilation well,
249-
// so we ignore groups (tests suffixed with _1 and _2)
250-
override def groupedFiles(sources: List[File]): List[List[File]] = {
251-
val grouped = sources groupBy (_.group)
252-
val flatGroup = List(grouped.keys.toList.sorted.map({ k => grouped(k) sortBy (_.getName) }).flatten)
253-
try { // try/catch because of bug in partest that throws exception
254-
if (flatGroup != super.groupedFiles(sources))
255-
throw new java.lang.UnsupportedOperationException()
256-
} catch {
257-
case e: java.lang.UnsupportedOperationException =>
258-
val genlogFWriter = new FileWriter(DPConfig.genLog.jfile, true)
259-
val genlogWriter = new PrintWriter(genlogFWriter, true)
260-
genlogWriter.println("Warning: Overriding compilation groups for tests: " + sources)
261-
genlogWriter.close
262-
genlogFWriter.close
263-
}
264-
flatGroup
265-
}
266-
267-
// override to avoid separate compilation of scala and java sources
268-
override def mixedCompileGroup(allFiles: List[File]): List[CompileRound] = List(OnlyDotty(allFiles))
269-
case class OnlyDotty(fs: List[File]) extends CompileRound {
270-
def description = s"dotc $fsString"
271-
lazy val result = { pushTranscript(description) ; attemptCompile(fs) }
272-
}
273-
274304
// override to add dotty and scala jars to classpath
275305
override def extraClasspath = suiteRunner.fileManager.asInstanceOf[DottyFileManager].extraJarList ::: super.extraClasspath
276306

test/test/CompilerTest.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,8 @@ abstract class CompilerTest {
410410
nr: Int = 0, oldOutput: String = defaultOutputDir): Unit = {
411411

412412
val partestOutput = dest.jfile.getParentFile + JFile.separator + dest.stripExtension + "-" + kind + ".obj"
413-
val flags = oldFlags.map(f => if (f == oldOutput) partestOutput else f)
413+
val flags = oldFlags.map(f => if (f == oldOutput) partestOutput else f) ++
414+
List(s"-classpath $partestOutput") // Required for separate compilation tests
414415

415416
getExisting(dest).isDifferent(source, flags, nerr) match {
416417
case NotExists => copyFiles(source, dest, partestOutput, flags, nerr, kind)

tests/pos/annot.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Test {
99

1010
@SuppressWarnings(Array("hi", "foo")) def foo2() = ??? //can be deferred as there is a non-generic method
1111

12-
@SuppressWarnings("hi") def foo3() = ??? // can be written in java and is serialized this way in bytecode. doesn't typecheck
12+
@SuppressWarnings(Array("hi")) def foo3() = ??? // can be written in java and is serialized this way in bytecode. doesn't typecheck
1313

1414
@Transient(false) def bar = ???
1515

tests/run/colltest4/CollectionStrawMan4_1.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
package colltest4
12
package strawman.collections
23

34
import Predef.{augmentString => _, wrapString => _, _}
@@ -216,7 +217,7 @@ object CollectionStrawMan4 {
216217
def fromIterable[B](coll: Iterable[B]): ListBuffer[B] = coll match {
217218
case pd @ View.Partitioned(partition: View.Partition[B]) =>
218219
partition.distribute(new ListBuffer[B]())
219-
pd.forced.get.asInstanceOf[ListBuffer[B]]
220+
new ListBuffer[B] ++= pd.forced.get
220221
case _ =>
221222
new ListBuffer[B] ++= coll
222223
}

tests/run/colltest4/CollectionTests_2.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import Predef.{augmentString => _, wrapString => _, _}
22
import scala.reflect.ClassTag
33

44
object Test {
5-
import strawman.collections._
6-
import CollectionStrawMan5._
5+
import colltest4.strawman.collections._
6+
import CollectionStrawMan4._
77

88
def seqOps(xs: Seq[Int]) = {
99
val x1 = xs.foldLeft("")(_ + _)

tests/run/colltest5/CollectionStrawMan5_1.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
package colltest5
12
package strawman.collections
23

34
import Predef.{augmentString => _, wrapString => _, _}

tests/run/colltest5/CollectionTests_2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Predef.{augmentString => _, wrapString => _, _}
22
import scala.reflect.ClassTag
33

44
object Test {
5-
import strawman.collections._
5+
import colltest5.strawman.collections._
66
import CollectionStrawMan5._
77

88
def seqOps(xs: Seq[Int]) = {

0 commit comments

Comments
 (0)