Skip to content

Commit 387417a

Browse files
Merge branch 'master' into add-transparent-7
2 parents 48ea248 + a2a1112 commit 387417a

File tree

35 files changed

+670
-128
lines changed

35 files changed

+670
-128
lines changed

.drone.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,23 @@ pipeline:
2323
# We run tests in parallel. Tests run in a copy of the working directory to avoid conflict
2424
test:
2525
group: test
26-
image: lampepfl/dotty:2018-08-31
26+
image: lampepfl/dotty:2018-09-14-2
2727
commands:
2828
- cp -R . /tmp/1/ && cd /tmp/1/
2929
- ./project/scripts/sbt ";compile ;test"
3030
- ./project/scripts/cmdTests
3131

3232
test_bootstrapped:
3333
group: test
34-
image: lampepfl/dotty:2018-08-31
34+
image: lampepfl/dotty:2018-09-14-2
3535
commands:
3636
- cp -R . /tmp/2/ && cd /tmp/2/
3737
- ./project/scripts/sbt ";dotty-bootstrapped/compile ;dotty-bootstrapped/test"
3838
- ./project/scripts/bootstrapCmdTests
3939

4040
test_sbt:
4141
group: test
42-
image: lampepfl/dotty:2018-08-31
42+
image: lampepfl/dotty:2018-09-14-2
4343
commands:
4444
- cp -R . /tmp/4/ && cd /tmp/4/
4545
- ./project/scripts/sbt sbt-dotty/scripted
@@ -49,7 +49,7 @@ pipeline:
4949

5050
# DOCUMENTATION:
5151
documentation:
52-
image: lampepfl/dotty:2018-08-31
52+
image: lampepfl/dotty:2018-09-14-2
5353
commands:
5454
- ./project/scripts/genDocs
5555
secrets: [ bot_pass ]
@@ -61,7 +61,7 @@ pipeline:
6161
# PUBLISHING:
6262
# Publishing expect NIGHTLYBUILD or RELEASEBUILD to be set. See dottyVersion in Build.scala
6363
publish_nightly:
64-
image: lampepfl/dotty:2018-08-31
64+
image: lampepfl/dotty:2018-09-14-2
6565
environment:
6666
- NIGHTLYBUILD=yes
6767
commands:
@@ -72,7 +72,7 @@ pipeline:
7272
environment: nightly
7373

7474
publish_release:
75-
image: lampepfl/dotty:2018-08-31
75+
image: lampepfl/dotty:2018-09-14-2
7676
environment:
7777
- RELEASEBUILD=yes
7878
commands:
@@ -96,7 +96,7 @@ pipeline:
9696
event: tag
9797

9898
publish_sbt_release:
99-
image: lampepfl/dotty:2018-08-31
99+
image: lampepfl/dotty:2018-09-14-2
100100
environment:
101101
- RELEASEBUILD=yes
102102
commands:

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,10 @@ class Definitions {
422422
def Seq_drop(implicit ctx: Context) = Seq_dropR.symbol
423423
lazy val Seq_lengthCompareR = SeqClass.requiredMethodRef(nme.lengthCompare)
424424
def Seq_lengthCompare(implicit ctx: Context) = Seq_lengthCompareR.symbol
425+
lazy val Seq_lengthR = SeqClass.requiredMethodRef(nme.length)
426+
def Seq_length(implicit ctx: Context) = Seq_lengthR.symbol
427+
lazy val Seq_toSeqR = SeqClass.requiredMethodRef(nme.toSeq)
428+
def Seq_toSeq(implicit ctx: Context) = Seq_toSeqR.symbol
425429

426430
lazy val ArrayType: TypeRef = ctx.requiredClassRef("scala.Array")
427431
def ArrayClass(implicit ctx: Context) = ArrayType.symbol.asClass

compiler/src/dotty/tools/dotc/tastyreflect/StandardDefinitions.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,6 @@ trait StandardDefinitions extends scala.tasty.reflect.StandardDefinitions {
8080
def ObjectType: Type = defn.ObjectType
8181
def NothingType: Type = defn.NothingType
8282
def NullType: Type = defn.NullType
83+
def StringType: Type = defn.StringType
8384
}
8485
}

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ object PatternMatcher {
254254
*/
255255
def matchElemsPlan(seqSym: Symbol, args: List[Tree], exact: Boolean, onSuccess: Plan) = {
256256
val selectors = args.indices.toList.map(idx =>
257-
ref(seqSym).select(nme.apply).appliedTo(Literal(Constant(idx))))
257+
ref(seqSym).select(defn.Seq_apply.matchingMember(seqSym.info)).appliedTo(Literal(Constant(idx))))
258258
TestPlan(LengthTest(args.length, exact), seqSym, seqSym.pos,
259259
matchArgsPlan(selectors, args, onSuccess))
260260
}
@@ -265,8 +265,13 @@ object PatternMatcher {
265265
def unapplySeqPlan(getResult: Symbol, args: List[Tree]): Plan = args.lastOption match {
266266
case Some(VarArgPattern(arg)) =>
267267
val matchRemaining =
268-
if (args.length == 1)
269-
patternPlan(getResult, arg, onSuccess)
268+
if (args.length == 1) {
269+
val toSeq = ref(getResult)
270+
.select(defn.Seq_toSeq.matchingMember(getResult.info))
271+
letAbstract(toSeq) { toSeqResult =>
272+
patternPlan(toSeqResult, arg, onSuccess)
273+
}
274+
}
270275
else {
271276
val dropped = ref(getResult)
272277
.select(defn.Seq_drop.matchingMember(getResult.info))
@@ -638,11 +643,18 @@ object PatternMatcher {
638643
case EqualTest(tree) =>
639644
tree.equal(scrutinee)
640645
case LengthTest(len, exact) =>
641-
scrutinee
642-
.select(defn.Seq_lengthCompare.matchingMember(scrutinee.tpe))
643-
.appliedTo(Literal(Constant(len)))
644-
.select(if (exact) defn.Int_== else defn.Int_>=)
645-
.appliedTo(Literal(Constant(0)))
646+
val lengthCompareSym = defn.Seq_lengthCompare.matchingMember(scrutinee.tpe)
647+
if (lengthCompareSym.exists)
648+
scrutinee
649+
.select(defn.Seq_lengthCompare.matchingMember(scrutinee.tpe))
650+
.appliedTo(Literal(Constant(len)))
651+
.select(if (exact) defn.Int_== else defn.Int_>=)
652+
.appliedTo(Literal(Constant(0)))
653+
else // try length
654+
scrutinee
655+
.select(defn.Seq_length.matchingMember(scrutinee.tpe))
656+
.select(if (exact) defn.Int_== else defn.Int_>=)
657+
.appliedTo(Literal(Constant(len)))
646658
case TypeTest(tpt) =>
647659
val expectedTp = tpt.tpe
648660

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

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,44 @@ object Applications {
101101
Nil
102102
}
103103

104+
/** If `getType` is of the form:
105+
* ```
106+
* {
107+
* def lengthCompare(len: Int): Int // or, def length: Int
108+
* def apply(i: Int): T = a(i)
109+
* def drop(n: Int): scala.Seq[T]
110+
* def toSeq: scala.Seq[T]
111+
* }
112+
* ```
113+
* returns `T`, otherwise NoType.
114+
*/
115+
def unapplySeqTypeElemTp(getTp: Type): Type = {
116+
def lengthTp = ExprType(defn.IntType)
117+
def lengthCompareTp = MethodType(List(defn.IntType), defn.IntType)
118+
def applyTp(elemTp: Type) = MethodType(List(defn.IntType), elemTp)
119+
def dropTp(elemTp: Type) = MethodType(List(defn.IntType), defn.SeqType.appliedTo(elemTp))
120+
def toSeqTp(elemTp: Type) = ExprType(defn.SeqType.appliedTo(elemTp))
121+
122+
// the result type of `def apply(i: Int): T`
123+
val elemTp = getTp.member(nme.apply).suchThat(_.info <:< applyTp(WildcardType)).info.resultType
124+
125+
def hasMethod(name: Name, tp: Type) =
126+
getTp.member(name).suchThat(getTp.memberInfo(_) <:< tp).exists
127+
128+
val isValid =
129+
elemTp.exists &&
130+
(hasMethod(nme.lengthCompare, lengthCompareTp) || hasMethod(nme.length, lengthTp)) &&
131+
hasMethod(nme.drop, dropTp(elemTp)) &&
132+
hasMethod(nme.toSeq, toSeqTp(elemTp))
133+
134+
if (isValid) elemTp else NoType
135+
}
136+
104137
if (unapplyName == nme.unapplySeq) {
105-
if (unapplyResult derivesFrom defn.SeqClass)
106-
seqSelector :: Nil
107-
else if (isGetMatch(unapplyResult, pos) && getTp.derivesFrom(defn.SeqClass)) {
108-
val seqArg = (if (ctx.isDependent) getTp.widenTermRefExpr.annotatedToRepeated.dealiasKeepAnnots else getTp)
109-
.elemType.hiBound
110-
if (seqArg.exists) args.map(Function.const(seqArg))
138+
if (isGetMatch(unapplyResult, pos)) {
139+
val depGetTp = if (ctx.isDependent) getTp.widenTermRefExpr.annotatedToRepeated.dealiasKeepAnnots else getTp
140+
val elemTp = unapplySeqTypeElemTp(depGetTp)
141+
if (elemTp.exists) args.map(Function.const(elemTp))
111142
else fail
112143
}
113144
else fail

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,20 @@ object RefChecks {
108108
case _ =>
109109
}
110110

111+
/** Disallow using trait parameters as prefix for its parents.
112+
*
113+
* The rationale is to ensure outer-related NPE never happen in Scala.
114+
* Otherwise, outer NPE may happen, see tests/neg/i5083.scala
115+
*/
116+
private def checkParentPrefix(cls: Symbol, parent: Tree)(implicit ctx: Context): Unit =
117+
parent.tpe.typeConstructor match {
118+
case TypeRef(ref: TermRef, _) =>
119+
val paramRefs = ref.namedPartsWith(ntp => ntp.symbol.enclosingClass == cls)
120+
if (paramRefs.nonEmpty)
121+
ctx.error("trait parameters cannot be used as parent prefixes", parent.pos)
122+
case _ =>
123+
}
124+
111125
/** Check that a class and its companion object to not both define
112126
* a class or module with same name
113127
*/
@@ -961,6 +975,7 @@ class RefChecks extends MiniPhase { thisPhase =>
961975
val cls = ctx.owner
962976
checkOverloadedRestrictions(cls)
963977
checkParents(cls)
978+
if (cls.is(Trait)) tree.parents.foreach(checkParentPrefix(cls, _))
964979
checkCompanionNameClashes(cls)
965980
checkAllOverrides(cls)
966981
tree

compiler/test/dotc/run-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,4 @@ typelevel-patmat.scala
8383
typelevel.scala
8484
typelevel1.scala
8585
typelevel3.scala
86+
xml-interpolation

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import java.util.HashMap
88
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
99
import java.nio.file.{Files, NoSuchFileException, Path, Paths}
1010
import java.util.concurrent.{TimeUnit, TimeoutException, Executors => JExecutors}
11+
import java.util.{Timer, TimerTask}
1112

1213
import scala.io.Source
1314
import scala.util.control.NonFatal
@@ -285,11 +286,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
285286
realStderr.println(msg + paddingRight)
286287
}
287288

288-
/** A single `Runnable` that prints a progress bar for the curent `Test` */
289-
private def createProgressMonitor: Runnable = () => {
289+
/** Print a progress bar for the curent `Test` */
290+
private def updateProgressMonitor(): Unit = {
290291
val start = System.currentTimeMillis
291292
var tCompiled = testSourcesCompleted
292-
while (tCompiled < sourceCount) {
293+
if (tCompiled < sourceCount) {
293294
val timestamp = (System.currentTimeMillis - start) / 1000
294295
val progress = (tCompiled.toDouble / sourceCount * 40).toInt
295296

@@ -299,16 +300,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
299300
(" " * (39 - progress)) +
300301
s"] completed ($tCompiled/$sourceCount, $failureCount failed, ${timestamp}s)\r"
301302
)
302-
303-
Thread.sleep(100)
304-
tCompiled = testSourcesCompleted
305303
}
306-
307-
val timestamp = (System.currentTimeMillis - start) / 1000
308-
// println, otherwise no newline and cursor at start of line
309-
realStdout.println(
310-
s"[=======================================] completed ($sourceCount/$sourceCount, $failureCount failed, ${timestamp}s)"
311-
)
304+
else {
305+
val timestamp = (System.currentTimeMillis - start) / 1000
306+
// println, otherwise no newline and cursor at start of line
307+
realStdout.print(
308+
s"[=======================================] completed ($sourceCount/$sourceCount, $failureCount failed, ${timestamp}s)\r"
309+
)
310+
}
312311
}
313312

314313
/** Wrapper function to make sure that the compiler itself did not crash -
@@ -465,7 +464,14 @@ trait ParallelTesting extends RunnerOrchestration { self =>
465464
case None => JExecutors.newWorkStealingPool()
466465
}
467466

468-
if (isInteractive && !suppressAllOutput) pool.submit(createProgressMonitor)
467+
val timer = new Timer()
468+
val logProgress = isInteractive && !suppressAllOutput
469+
if (logProgress) {
470+
val task = new TimerTask {
471+
def run() = updateProgressMonitor()
472+
}
473+
timer.schedule(task, 100, 200)
474+
}
469475

470476
val eventualResults = filteredSources.map { target =>
471477
pool.submit(encapsulatedCompilation(target))
@@ -481,6 +487,12 @@ trait ParallelTesting extends RunnerOrchestration { self =>
481487

482488
eventualResults.foreach(_.get)
483489

490+
if (logProgress) {
491+
timer.cancel()
492+
// update progress one last time
493+
updateProgressMonitor()
494+
}
495+
484496
if (didFail) {
485497
reportFailed()
486498
failedTestSources.toSet.foreach(addFailedTest)

docs/docs/reference/changed/pattern-matching.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,23 @@ object FirstChars {
6363
```
6464

6565

66-
## Seq Pattern
66+
## Name-based Seq Pattern
6767

6868
- Extractor defines `def unapplySeq(x: T): U`
6969
- `U` has (parameterless `def` or `val`) members `isEmpty: Boolean` and `get: S`
70-
- `S <: Seq[V]`
71-
- Pattern-matching on `N` pattern with types `V, V, ..., V`, where `N` is the runtime size of the `Seq`.
70+
- `S` conforms to `X`, `T2` and `T3` conform to `T1`
71+
72+
```Scala
73+
type X = {
74+
def lengthCompare(len: Int): Int // or, `def length: Int`
75+
def apply(i: Int): T1
76+
def drop(n: Int): scala.Seq[T2]
77+
def toSeq: scala.Seq[T3]
78+
}
79+
```
80+
81+
- Pattern-matching on _exactly_ `N` simple patterns with types `T1, T1, ..., T1`, where `N` is the runtime size of the sequence, or
82+
- Pattern-matching on `>= N` simple patterns and _a vararg pattern_ (e.g., `xs: _*`) with types `T1, T1, ..., T1, Seq[T1]`, where `N` is the minimum size of the sequence.
7283

7384
<!-- To be kept in sync with tests/new/patmat-spec.scala -->
7485

@@ -87,7 +98,7 @@ object CharList {
8798
```
8899

89100

90-
## Name Based Pattern
101+
## Name-based Pattern
91102

92103
- Extractor defines `def unapply(x: T): U`
93104
- `U` has (parameterless `def` or `val`) members `isEmpty: Boolean` and `get: S`

language-server/test/dotty/tools/languageserver/util/server/TestFile.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import java.nio.file.{Path, Paths}
55
import org.eclipse.lsp4j.TextDocumentIdentifier
66

77
class TestFile(val file: String) extends AnyVal {
8-
def uri: String = s"file://${TestFile.sourceDir}/$file"
8+
def uri: String = TestFile.sourceDir.resolve(file).toUri.toString
99
}
1010

1111
object TestFile {

language-server/test/dotty/tools/languageserver/util/server/TestServer.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,18 @@ class TestServer(testFolder: Path) {
1515

1616
private[this] def init(): InitializeResult = {
1717
// Fill the configuration with values populated by sbt
18-
def showSeq[T](lst: Seq[T]): String = lst.map(elem => '"' + elem.toString + '"').mkString("[ ", ", ", " ]")
18+
def showSeq[T](lst: Seq[T]): String =
19+
lst
20+
.map(elem => '"' + elem.toString.replace('\\', '/') + '"')
21+
.mkString("[ ", ", ", " ]")
1922
val dottyIdeJson: String =
2023
s"""[ {
2124
| "id" : "dotty-ide-test",
2225
| "compilerVersion" : "${BuildInfo.ideTestsCompilerVersion}",
2326
| "compilerArguments" : ${showSeq(BuildInfo.ideTestsCompilerArguments)},
2427
| "sourceDirectories" : ${showSeq(BuildInfo.ideTestsSourceDirectories)},
2528
| "dependencyClasspath" : ${showSeq(BuildInfo.ideTestsDependencyClasspath)},
26-
| "classDirectory" : "${BuildInfo.ideTestsClassDirectory}"
29+
| "classDirectory" : "${BuildInfo.ideTestsClassDirectory.toString.replace('\\','/')}"
2730
|}
2831
|]""".stripMargin
2932
val configFile = testFolder.resolve(DottyLanguageServer.IDE_CONFIG_FILE)

library/src/scala/tasty/reflect/StandardDefinitions.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,5 +212,8 @@ trait StandardDefinitions extends TastyCore {
212212

213213
/** The type of core type `Null`. */
214214
def NullType: Type
215+
216+
/** The type for `scala.String`. */
217+
def StringType: Type
215218
}
216219
}

0 commit comments

Comments
 (0)