Skip to content

Commit 5e4b950

Browse files
authored
Merge branch 'lampepfl:main' into main
2 parents 2c6e613 + 86bb972 commit 5e4b950

File tree

130 files changed

+1126
-214
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+1126
-214
lines changed

.github/workflows/language-reference.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ jobs:
2121
uses: actions/checkout@v3
2222
with:
2323
path: 'dotty'
24-
ref: 'language-reference-stable'
2524
fetch-depth: 0
2625
ssh-key: ${{ secrets.DOCS_KEY }}
2726

@@ -45,7 +44,7 @@ jobs:
4544
- name: Generate reference documentation and test links
4645
run: |
4746
cd dotty
48-
./project/scripts/sbt scaladoc/generateReferenceDocumentation --no-regenerate-expected-links
47+
./project/scripts/sbt "scaladoc/generateReferenceDocumentation --no-regenerate-expected-links"
4948
./project/scripts/docsLinksStability ./scaladoc/output/reference ./project/scripts/expected-links/reference-expected-links.txt
5049
cd ..
5150

.github/workflows/scaladoc.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
run: ./project/scripts/sbt scaladoc/generateTestcasesDocumentation
5858

5959
- name: Generate reference documentation
60-
run: ./project/scripts/sbt scaladoc/generateReferenceDocumentation --no-regenerate-expected-links
60+
run: ./project/scripts/sbt scaladoc/generateReferenceDocumentation
6161

6262
- name: Generate Scala 3 documentation
6363
run: ./project/scripts/sbt scaladoc/generateScalaDocumentation

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,6 @@
219219
[submodule "community-build/community-projects/http4s"]
220220
path = community-build/community-projects/http4s
221221
url = https://github.com/dotty-staging/http4s.git
222+
[submodule "community-build/community-projects/parboiled2"]
223+
path = community-build/community-projects/parboiled2
224+
url = https://github.com/dotty-staging/parboiled2.git
Submodule parboiled2 added at 6281277

community-build/src/scala/dotty/communitybuild/projects.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,14 @@ object projects:
761761
dependencies = List(cats, catsEffect3, fs2, disciplineMunit, scalacheckEffect)
762762
)
763763

764+
lazy val parboiled2 = SbtCommunityProject(
765+
project = "parboiled2",
766+
sbtTestCommand = "parboiledCoreJVM/test; parboiledJVM/test",
767+
sbtPublishCommand = "publishLocal",
768+
scalacOptions = SbtCommunityProject.scalacOptions.filter(_ != "-Xcheck-macros"),
769+
dependencies = List(utest, scalacheck)
770+
)
771+
764772
end projects
765773

766774
def allProjects = List(
@@ -841,7 +849,8 @@ def allProjects = List(
841849
projects.specs2,
842850
projects.coop,
843851
projects.spire,
844-
projects.http4s
852+
projects.http4s,
853+
projects.parboiled2,
845854
)
846855

847856
lazy val projectMap = allProjects.groupBy(_.project)

community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class CommunityBuildTestC:
7474
@Test def onnxScala = projects.onnxScala.run()
7575
@Test def oslib = projects.oslib.run()
7676
// @Test def oslibWatch = projects.oslibWatch.run()
77+
@Test def parboiled2 = projects.parboiled2.run()
7778
@Test def playJson = projects.playJson.run()
7879
@Test def pprint = projects.pprint.run()
7980
@Test def protoquill = projects.protoquill.run()

compiler/src/dotty/tools/dotc/ast/MainProxies.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,10 @@ object MainProxies {
242242
val param = paramName.toString
243243
val paramType0 = if formal.isRepeatedParam then formal.argTypes.head.dealias else formal.dealias
244244
val paramType = paramType0.dealias
245-
246-
val paramTypeStr = formal.dealias.typeSymbol.owner.showFullName + "." + paramType.show
245+
val paramTypeOwner = paramType.typeSymbol.owner
246+
val paramTypeStr =
247+
if paramTypeOwner == defn.EmptyPackageClass then paramType.show
248+
else paramTypeOwner.showFullName + "." + paramType.show
247249
val hasDefault = defaultValueSymbols.contains(idx)
248250
val isRepeated = formal.isRepeatedParam
249251
val paramDoc = documentation.argDocs.getOrElse(param, "")

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -578,12 +578,12 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
578578
pre
579579
case _ =>
580580
tree1
581-
581+
582582
val countsAsPure =
583583
if dropOp(tree1).symbol.isInlineVal
584584
then isIdempotentExpr(tree1)
585585
else isPureExpr(tree1)
586-
586+
587587
if countsAsPure then Literal(value).withSpan(tree.span)
588588
else
589589
val pre = dropOp(tree1)
@@ -864,8 +864,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
864864
* that is not a member of an underlying class or trait?
865865
*/
866866
def isStructuralTermSelectOrApply(tree: Tree)(using Context): Boolean = {
867-
def isStructuralTermSelect(tree: Select) = {
868-
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match {
867+
def isStructuralTermSelect(tree: Select) =
868+
def hasRefinement(qualtpe: Type): Boolean = qualtpe.dealias match
869869
case RefinedType(parent, rname, rinfo) =>
870870
rname == tree.name || hasRefinement(parent)
871871
case tp: TypeProxy =>
@@ -876,17 +876,21 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
876876
hasRefinement(tp.tp1) || hasRefinement(tp.tp2)
877877
case _ =>
878878
false
879+
!tree.symbol.exists
880+
&& tree.isTerm
881+
&& {
882+
val qualType = tree.qualifier.tpe
883+
hasRefinement(qualType) && !qualType.derivesFrom(defn.PolyFunctionClass)
879884
}
880-
!tree.symbol.exists && tree.isTerm && hasRefinement(tree.qualifier.tpe)
881-
}
882-
def loop(tree: Tree): Boolean = tree match {
885+
def loop(tree: Tree): Boolean = tree match
886+
case TypeApply(fun, _) =>
887+
loop(fun)
883888
case Apply(fun, _) =>
884889
loop(fun)
885890
case tree: Select =>
886891
isStructuralTermSelect(tree)
887892
case _ =>
888893
false
889-
}
890894
loop(tree)
891895
}
892896

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,13 @@ object TypeErasure {
363363
* which leads to more predictable bytecode and (?) faster dynamic dispatch.
364364
*/
365365
def erasedLub(tp1: Type, tp2: Type)(using Context): Type = {
366-
// After erasure, C | {Null, Nothing} is just C, if C is a reference type.
367-
// We need to short-circuit this case here because the regular lub logic below
368-
// relies on the class hierarchy, which doesn't properly capture `Null`s subtyping
369-
// behaviour.
370-
if (tp1.isBottomTypeAfterErasure && tp2.derivesFrom(defn.ObjectClass)) return tp2
371-
if (tp2.isBottomTypeAfterErasure && tp1.derivesFrom(defn.ObjectClass)) return tp1
372-
tp1 match {
366+
// We need to short-circuit the following 2 case because the regular lub logic in the else relies on
367+
// the class hierarchy, which doesn't properly capture `Nothing`/`Null` subtyping behaviour.
368+
if tp1.isRef(defn.NothingClass) || (tp1.isRef(defn.NullClass) && tp2.derivesFrom(defn.ObjectClass)) then
369+
tp2 // After erasure, Nothing | T is just T and Null | C is just C, if C is a reference type.
370+
else if tp2.isRef(defn.NothingClass) || (tp2.isRef(defn.NullClass) && tp1.derivesFrom(defn.ObjectClass)) then
371+
tp1 // After erasure, T | Nothing is just T and C | Null is just C, if C is a reference type.
372+
else tp1 match {
373373
case JavaArrayType(elem1) =>
374374
import dotty.tools.dotc.transform.TypeUtils._
375375
tp2 match {

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,16 @@ class ClassfileParser(
11271127
val outerName = entry.strippedOuter
11281128
val innerName = entry.originalName
11291129
val owner = classNameToSymbol(outerName)
1130-
val result = atPhase(typerPhase)(getMember(owner, innerName.toTypeName))
1130+
val result = owner.denot.infoOrCompleter match
1131+
case _: StubInfo if hasAnnotation(entry.jflags) =>
1132+
requiredClass(innerName.toTypeName)
1133+
// It's okay for the classfiles of Java annotations to be missing
1134+
// from the classpath. If an annotation is defined as an inner class
1135+
// we need to avoid forcing the outer class symbol here, and instead
1136+
// return a new stub symbol for the inner class. This is tested by
1137+
// `surviveMissingInnerClassAnnot` in AnnotationsTests.scala
1138+
case _ =>
1139+
atPhase(typerPhase)(getMember(owner, innerName.toTypeName))
11311140
assert(result ne NoSymbol,
11321141
i"""failure to resolve inner class:
11331142
|externalName = ${entry.externalName},

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class TreeUnpickler(reader: TastyReader,
113113
class Completer(reader: TastyReader)(using @constructorOnly _ctx: Context) extends LazyType {
114114
import reader._
115115
val owner = ctx.owner
116+
val mode = ctx.mode
116117
val source = ctx.source
117118
def complete(denot: SymDenotation)(using Context): Unit =
118119
def fail(ex: Throwable) =
@@ -129,7 +130,7 @@ class TreeUnpickler(reader: TastyReader,
129130
try
130131
atPhaseBeforeTransforms {
131132
new TreeReader(reader).readIndexedDef()(
132-
using ctx.withOwner(owner).withSource(source))
133+
using ctx.withOwner(owner).withModeBits(mode).withSource(source))
133134
}
134135
catch
135136
case ex: AssertionError => fail(ex)
@@ -1193,6 +1194,10 @@ class TreeUnpickler(reader: TastyReader,
11931194
res.withAttachment(SuppressedApplyToNone, ())
11941195
else res
11951196

1197+
def simplifyLub(tree: Tree): Tree =
1198+
tree.overwriteType(tree.tpe.simplified)
1199+
tree
1200+
11961201
def readLengthTerm(): Tree = {
11971202
val end = readEnd()
11981203
val result =
@@ -1242,23 +1247,25 @@ class TreeUnpickler(reader: TastyReader,
12421247
val tpt = ifBefore(end)(readTpt(), EmptyTree)
12431248
Closure(Nil, meth, tpt)
12441249
case MATCH =>
1245-
if (nextByte == IMPLICIT) {
1246-
readByte()
1247-
InlineMatch(EmptyTree, readCases(end))
1248-
}
1249-
else if (nextByte == INLINE) {
1250-
readByte()
1251-
InlineMatch(readTerm(), readCases(end))
1252-
}
1253-
else Match(readTerm(), readCases(end))
1250+
simplifyLub(
1251+
if (nextByte == IMPLICIT) {
1252+
readByte()
1253+
InlineMatch(EmptyTree, readCases(end))
1254+
}
1255+
else if (nextByte == INLINE) {
1256+
readByte()
1257+
InlineMatch(readTerm(), readCases(end))
1258+
}
1259+
else Match(readTerm(), readCases(end)))
12541260
case RETURN =>
12551261
val from = readSymRef()
12561262
val expr = ifBefore(end)(readTerm(), EmptyTree)
12571263
Return(expr, Ident(from.termRef))
12581264
case WHILE =>
12591265
WhileDo(readTerm(), readTerm())
12601266
case TRY =>
1261-
Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree))
1267+
simplifyLub(
1268+
Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree)))
12621269
case SELECTouter =>
12631270
val levels = readNat()
12641271
readTerm().outerSelect(levels, SkolemType(readType()))

compiler/src/dotty/tools/dotc/interactive/Completion.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,10 @@ object Completion {
384384
if qual.tpe.isExactlyNothing || qual.tpe.isNullType then
385385
Map.empty
386386
else
387-
val membersFromConversion =
388-
implicitConversionTargets(qual)(using ctx.fresh.setExploreTyperState()).flatMap(accessibleMembers)
389-
membersFromConversion.toSeq.groupByName
387+
implicitConversionTargets(qual)(using ctx.fresh.setExploreTyperState())
388+
.flatMap(accessibleMembers)
389+
.toSeq
390+
.groupByName
390391

391392
/** Completions from extension methods */
392393
private def extensionCompletions(qual: Tree)(using Context): CompletionMap =
@@ -492,15 +493,17 @@ object Completion {
492493

493494
/**
494495
* Given `qual` of type T, finds all the types S such that there exists an implicit conversion
495-
* from T to S.
496+
* from T to S. It then applies conversion method for proper type parameter resolution.
496497
*
497498
* @param qual The argument to which the implicit conversion should be applied.
498-
* @return The set of types that `qual` can be converted to.
499+
* @return The set of types after `qual` implicit conversion.
499500
*/
500501
private def implicitConversionTargets(qual: Tree)(using Context): Set[Type] = {
501502
val typer = ctx.typer
502503
val conversions = new typer.ImplicitSearch(defn.AnyType, qual, pos.span).allImplicits
503-
val targets = conversions.map(_.widen.finalResultType)
504+
val convertedTrees = conversions.flatMap(typer.tryApplyingImplicitConversion(_, qual))
505+
val targets = convertedTrees.map(_.tpe.finalResultType)
506+
504507
interactiv.println(i"implicit conversion targets considered: ${targets.toList}%, %")
505508
targets
506509
}

compiler/src/dotty/tools/dotc/interactive/Interactive.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ object Interactive {
7979
def enclosingTree(trees: List[SourceTree], pos: SourcePosition)(using Context): Tree =
8080
enclosingTree(pathTo(trees, pos))
8181

82-
/** The closes enclosing tree with a symbol, or the `EmptyTree`.
82+
/** The closest enclosing tree with a symbol, or the `EmptyTree`.
8383
*/
8484
def enclosingTree(path: List[Tree])(using Context): Tree =
8585
path.dropWhile(!_.symbol.exists).headOption.getOrElse(tpd.EmptyTree)

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3888,7 +3888,7 @@ object Parsers {
38883888
stats +++= defOrDcl(in.offset, defAnnotsMods(modifierTokens))
38893889
else
38903890
empty = true
3891-
statSepOrEnd(stats, empty, "toplevel definition")
3891+
statSepOrEnd(stats, noPrevStat = empty, "toplevel definition")
38923892
do ()
38933893
stats.toList
38943894
}
@@ -3938,7 +3938,7 @@ object Parsers {
39383938
stats += expr1()
39393939
else
39403940
empty = true
3941-
statSepOrEnd(stats, empty)
3941+
statSepOrEnd(stats, noPrevStat = empty)
39423942
do ()
39433943
(self, if stats.isEmpty then List(EmptyTree) else stats.toList)
39443944
}
@@ -3977,7 +3977,7 @@ object Parsers {
39773977
stats ++= checkLegal(defOrDcl(in.offset, Modifiers()))
39783978
var what = "declaration"
39793979
if inFunReturnType then what += " (possible cause: missing `=` in front of current method body)"
3980-
statSepOrEnd(stats, !dclFound, what)
3980+
statSepOrEnd(stats, noPrevStat = !dclFound, what)
39813981
do ()
39823982
stats.toList
39833983
}
@@ -4016,7 +4016,7 @@ object Parsers {
40164016
stats +++= localDef(in.offset)
40174017
else
40184018
empty = true
4019-
statSepOrEnd(stats, empty, altEnd = CASE)
4019+
statSepOrEnd(stats, noPrevStat = empty, altEnd = CASE)
40204020
do ()
40214021
stats.toList
40224022
}

compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID]:
176176
MatchableWarningID,
177177
CannotExtendFunctionID,
178178
LossyWideningConstantConversionID,
179-
ImplicitSearchTooLargeID
179+
ImplicitSearchTooLargeID,
180+
TargetNameOnTopLevelClassID
180181

181182
def errorNumber = ordinal - 2
182183

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2540,3 +2540,24 @@ import transform.SymUtils._
25402540
|
25412541
|${openSearchPairs.reverse.map(showQuery)}%\n%
25422542
"""
2543+
2544+
class TargetNameOnTopLevelClass(symbol: Symbol)(using Context)
2545+
extends SyntaxMsg(TargetNameOnTopLevelClassID):
2546+
def msg = em"${hl("@targetName")} annotation not allowed on top-level $symbol"
2547+
def explain =
2548+
val annot = symbol.getAnnotation(defn.TargetNameAnnot).get
2549+
em"""The @targetName annotation may be applied to a top-level ${hl("val")} or ${hl("def")}, but not
2550+
|a top-level ${hl("class")}, ${hl("trait")}, or ${hl("object")}.
2551+
|
2552+
|This restriction is due to the naming convention of Java classfiles, whose filenames
2553+
|are based on the name of the class defined within. If @targetName were permitted
2554+
|here, the name of the classfile would be based on the target name, and the compiler
2555+
|could not associate that classfile with the Scala-visible defined name of the class.
2556+
|
2557+
|If your use case requires @targetName, consider wrapping $symbol in an ${hl("object")}
2558+
|(and possibly exporting it), as in the following example:
2559+
|
2560+
|${hl("object Wrapper:")}
2561+
| $annot $symbol { ... }
2562+
|
2563+
|${hl("export")} Wrapper.${symbol.name} ${hl("// optional")}"""

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ object SymUtils:
120120
def useCompanionAsSumMirror(using Context): Boolean =
121121
def companionExtendsSum(using Context): Boolean =
122122
self.linkedClass.isSubClass(defn.Mirror_SumClass)
123-
self.linkedClass.exists
124-
&& !self.is(Scala2x)
123+
!self.is(Scala2x)
124+
&& self.linkedClass.exists
125+
&& !self.linkedClass.is(Case)
125126
&& (
126127
// If the sum type is compiled from source, and `self` is a "generic sum"
127128
// then its companion object will become a sum mirror in `posttyper`. (This method

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import Contexts._
99
import Symbols._
1010
import Names.Name
1111

12+
import dotty.tools.dotc.core.Decorators.*
13+
1214
object TypeUtils {
1315
/** A decorator that provides methods on types
1416
* that are needed in the transformer pipeline.
@@ -84,11 +86,16 @@ object TypeUtils {
8486
/** The TermRef referring to the companion of the underlying class reference
8587
* of this type, while keeping the same prefix.
8688
*/
87-
def companionRef(using Context): TermRef = self match {
89+
def mirrorCompanionRef(using Context): TermRef = self match {
90+
case OrType(tp1, tp2) =>
91+
val r1 = tp1.mirrorCompanionRef
92+
val r2 = tp2.mirrorCompanionRef
93+
assert(r1.symbol == r2.symbol, em"mirrorCompanionRef mismatch for $self: $r1, $r2 did not have the same symbol")
94+
r1
8895
case self @ TypeRef(prefix, _) if self.symbol.isClass =>
8996
prefix.select(self.symbol.companionModule).asInstanceOf[TermRef]
9097
case self: TypeProxy =>
91-
self.underlying.companionRef
98+
self.underlying.mirrorCompanionRef
9299
}
93100

94101
/** Is this type a methodic type that takes implicit parameters (both old and new) at some point? */

0 commit comments

Comments
 (0)