Skip to content

Commit 25cf4ed

Browse files
authored
Merge branch 'lampepfl:main' into show-context-for-inline-safe-init
2 parents 18300d0 + c04f566 commit 25cf4ed

File tree

34 files changed

+432
-456
lines changed

34 files changed

+432
-456
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,6 @@
247247
[submodule "community-build/community-projects/scalacheck-forward-compat"]
248248
path = community-build/community-projects/scalacheck-forward-compat
249249
url = https://github.com/dotty-staging/scalacheck
250+
[submodule "community-build/community-projects/http4s"]
251+
path = community-build/community-projects/http4s
252+
url = https://github.com/dotty-staging/http4s.git
Submodule http4s added at fc0a18d

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,14 @@ object projects:
791791
dependencies = () => List(cats, disciplineMunit)
792792
)
793793

794+
lazy val http4s = SbtCommunityProject(
795+
project = "http4s",
796+
sbtTestCommand = "tests/test; server/test; client/test; ember-core/test; ember-server/test; ember-client/test; circe/test",
797+
sbtPublishCommand = "publishLocal",
798+
scalacOptions = SbtCommunityProject.scalacOptions.filter(_ != "-Ysafe-init"),
799+
dependencies = () => List(cats, catsEffect3, fs2, disciplineMunit, scalacheckEffect)
800+
)
801+
794802
end projects
795803

796804
lazy val forwardCompatMapping = Map[CommunityProject, CommunityProject](
@@ -892,7 +900,9 @@ def allProjects = List(
892900
projects.jacksonModuleScala,
893901
projects.specs2,
894902
projects.coop,
895-
projects.coopForwardCompat
903+
projects.coopForwardCompat,
904+
projects.spire,
905+
projects.http4s
896906
)
897907

898908
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
@@ -52,6 +52,7 @@ class CommunityBuildTestB:
5252
@Test def scodecBits = projects.scodecBits.run()
5353
@Test def simulacrumScalafixAnnotations = projects.simulacrumScalafixAnnotations.run()
5454
@Test def spire = projects.spire.run()
55+
@Test def http4s = projects.http4s.run()
5556
end CommunityBuildTestB
5657

5758
@Category(Array(classOf[TestCategory]))

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4563,14 +4563,7 @@ class JSCodeGen()(using genCtx: Context) {
45634563
val module = annot.argumentConstantString(0).getOrElse {
45644564
unexpected("could not read the module argument as a string literal")
45654565
}
4566-
val path = annot.argumentConstantString(1).fold {
4567-
if (annot.arguments.sizeIs < 2)
4568-
parsePath(sym.defaultJSName)
4569-
else
4570-
Nil
4571-
} { pathName =>
4572-
parsePath(pathName)
4573-
}
4566+
val path = annot.argumentConstantString(1).fold[List[String]](Nil)(parsePath)
45744567
val importSpec = Import(module, path)
45754568
annot.argumentConstantString(2).fold[js.JSNativeLoadSpec] {
45764569
importSpec

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

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ object Completion {
7878
Mode.None
7979
}
8080

81+
/** When dealing with <errors> in varios palces we check to see if they are
82+
* due to incomplete backticks. If so, we ensure we get the full prefix
83+
* including the backtick.
84+
*
85+
* @param content The source content that we'll check the positions for the prefix
86+
* @param start The start position we'll start to look for the prefix at
87+
* @param end The end position we'll look for the prefix at
88+
* @return Either the full prefix including the ` or an empty string
89+
*/
90+
private def checkBacktickPrefix(content: Array[Char], start: Int, end: Int): String =
91+
content.lift(start) match
92+
case Some(char) if char == '`' =>
93+
content.slice(start, end).mkString
94+
case _ =>
95+
""
96+
8197
/**
8298
* Inspect `path` to determine the completion prefix. Only symbols whose name start with the
8399
* returned prefix should be considered.
@@ -92,15 +108,14 @@ object Completion {
92108
completionPrefix(selector :: Nil, pos)
93109
}.getOrElse("")
94110

95-
// We special case Select here because we want to determine if the name
96-
// is an error due to an unclosed backtick.
97-
case (select: untpd.Select) :: _ if (select.name == nme.ERROR) =>
98-
val content = select.source.content()
99-
content.lift(select.nameSpan.start) match
100-
case Some(char) if char == '`' =>
101-
content.slice(select.nameSpan.start, select.span.end).mkString
102-
case _ =>
103-
""
111+
// Foo.`se<TAB> will result in Select(Ident(Foo), <error>)
112+
case (select: untpd.Select) :: _ if select.name == nme.ERROR =>
113+
checkBacktickPrefix(select.source.content(), select.nameSpan.start, select.span.end)
114+
115+
// import scala.util.chaining.`s<TAB> will result in a Ident(<error>)
116+
case (ident: untpd.Ident) :: _ if ident.name == nme.ERROR =>
117+
checkBacktickPrefix(ident.source.content(), ident.span.start, ident.span.end)
118+
104119
case (ref: untpd.RefTree) :: _ =>
105120
if (ref.name == nme.ERROR) ""
106121
else ref.name.toString.take(pos.span.point - ref.span.point)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ object JavaParsers {
594594
val vparams = formalParams()
595595
if (!isVoid) rtpt = optArrayBrackets(rtpt)
596596
optThrows()
597-
val bodyOk = !inInterface || mods.isOneOf(Flags.DefaultMethod | Flags.JavaStatic)
597+
val bodyOk = !inInterface || mods.isOneOf(Flags.DefaultMethod | Flags.JavaStatic | Flags.Private)
598598
val body =
599599
if (bodyOk && in.token == LBRACE)
600600
methodBody()

compiler/src/dotty/tools/dotc/transform/sjs/PrepJSInterop.scala

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ import Contexts._
1414
import Decorators._
1515
import DenotTransformers._
1616
import Flags._
17-
import NameKinds.{DefaultGetterName, ModuleClassName}
18-
import NameOps._
17+
import NameKinds.DefaultGetterName
1918
import StdNames._
2019
import Symbols._
2120
import SymUtils._
@@ -560,14 +559,9 @@ class PrepJSInterop extends MacroTransform with IdentityDenotTransformer { thisP
560559
case Some(annot) if annot.symbol == jsdefn.JSGlobalAnnot =>
561560
checkJSGlobalLiteral(annot)
562561
val pathName = annot.argumentConstantString(0).getOrElse {
563-
val symTermName = sym.name.exclude(NameKinds.ModuleClassName).toTermName
564-
if (symTermName == nme.apply) {
562+
if ((enclosingOwner is OwnerKind.ScalaMod) && !sym.owner.isPackageObject) {
565563
report.error(
566-
"Native JS definitions named 'apply' must have an explicit name in @JSGlobal",
567-
annot.tree)
568-
} else if (symTermName.isSetterName) {
569-
report.error(
570-
"Native JS definitions with a name ending in '_=' must have an explicit name in @JSGlobal",
564+
"Native JS members inside non-native objects must have an explicit name in @JSGlobal",
571565
annot.tree)
572566
}
573567
sym.defaultJSName
@@ -576,18 +570,6 @@ class PrepJSInterop extends MacroTransform with IdentityDenotTransformer { thisP
576570

577571
case Some(annot) if annot.symbol == jsdefn.JSImportAnnot =>
578572
checkJSImportLiteral(annot)
579-
if (annot.arguments.sizeIs < 2) {
580-
val symTermName = sym.name.exclude(NameKinds.ModuleClassName).toTermName
581-
if (symTermName == nme.apply) {
582-
report.error(
583-
"Native JS definitions named 'apply' must have an explicit name in @JSImport",
584-
annot.tree)
585-
} else if (symTermName.isSetterName) {
586-
report.error(
587-
"Native JS definitions with a name ending in '_=' must have an explicit name in @JSImport",
588-
annot.tree)
589-
}
590-
}
591573
annot.argumentConstantString(2).foreach { globalPathName =>
592574
checkGlobalRefPath(globalPathName)
593575
}
@@ -1125,19 +1107,18 @@ object PrepJSInterop {
11251107
*/
11261108
private def checkJSImportLiteral(annot: Annotation)(using Context): Unit = {
11271109
val args = annot.arguments
1128-
val argCount = args.size
1129-
assert(argCount >= 1 && argCount <= 3,
1130-
i"@JSImport annotation $annot does not have between 1 and 3 arguments")
1110+
assert(args.size == 2 || args.size == 3,
1111+
i"@JSImport annotation $annot does not have exactly 2 or 3 arguments")
11311112

11321113
val firstArgIsValid = annot.argumentConstantString(0).isDefined
11331114
if (!firstArgIsValid)
11341115
report.error("The first argument to @JSImport must be a literal string.", args.head)
11351116

1136-
val secondArgIsValid = argCount < 2 || annot.argumentConstantString(1).isDefined || args(1).symbol == jsdefn.JSImportNamespaceModule
1117+
val secondArgIsValid = annot.argumentConstantString(1).isDefined || args(1).symbol == jsdefn.JSImportNamespaceModule
11371118
if (!secondArgIsValid)
11381119
report.error("The second argument to @JSImport must be literal string or the JSImport.Namespace object.", args(1))
11391120

1140-
val thirdArgIsValid = argCount < 3 || annot.argumentConstantString(2).isDefined
1121+
val thirdArgIsValid = args.size < 3 || annot.argumentConstantString(2).isDefined
11411122
if (!thirdArgIsValid)
11421123
report.error("The third argument to @JSImport, when present, must be a literal string.", args(2))
11431124
}

compiler/src/dotty/tools/repl/JLineTerminal.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ final class JLineTerminal extends java.io.Closeable {
152152
// using dummy values, resulting parsed input is probably unused
153153
defaultParsedLine
154154

155+
// In the situation where we have a partial command that we want to
156+
// complete we need to ensure that the :<partial-word> isn't split into
157+
// 2 tokens, but rather the entire thing is treated as the "word", in
158+
// order to insure the : is replaced in the completion.
159+
case ParseContext.COMPLETE if
160+
ParseResult.commands.exists(command => command._1.startsWith(input)) =>
161+
parsedLine(input, cursor)
162+
155163
case ParseContext.COMPLETE =>
156164
// Parse to find completions (typically after a Tab).
157165
def isCompletable(token: Token) = isIdentifier(token) || isKeyword(token)

compiler/src/dotty/tools/repl/ParseResult.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ object ParseResult {
127127
stats
128128
}
129129

130-
private val commands: List[(String, String => ParseResult)] = List(
130+
private[repl] val commands: List[(String, String => ParseResult)] = List(
131131
Quit.command -> (_ => Quit),
132132
Quit.alias -> (_ => Quit),
133133
Help.command -> (_ => Help),

compiler/src/dotty/tools/repl/ReplDriver.scala

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class ReplDriver(settings: Array[String],
205205
label
206206

207207
/** Extract possible completions at the index of `cursor` in `expr` */
208-
protected final def completions(cursor: Int, expr: String, state0: State): List[Candidate] = {
208+
protected final def completions(cursor: Int, expr: String, state0: State): List[Candidate] =
209209
def makeCandidate(label: String) = {
210210

211211
new Candidate(
@@ -218,20 +218,26 @@ class ReplDriver(settings: Array[String],
218218
/* complete = */ false // if true adds space when completing
219219
)
220220
}
221-
implicit val state = newRun(state0)
222-
compiler
223-
.typeCheck(expr, errorsAllowed = true)
224-
.map { tree =>
225-
val file = SourceFile.virtual("<completions>", expr, maybeIncomplete = true)
226-
val unit = CompilationUnit(file)(using state.context)
227-
unit.tpdTree = tree
228-
given Context = state.context.fresh.setCompilationUnit(unit)
229-
val srcPos = SourcePosition(file, Span(cursor))
230-
val (_, completions) = Completion.completions(srcPos)
231-
completions.map(_.label).distinct.map(makeCandidate)
221+
222+
if expr.startsWith(":") then
223+
ParseResult.commands.collect {
224+
case command if command._1.startsWith(expr) => makeCandidate(command._1)
232225
}
233-
.getOrElse(Nil)
234-
}
226+
else
227+
given state: State = newRun(state0)
228+
compiler
229+
.typeCheck(expr, errorsAllowed = true)
230+
.map { tree =>
231+
val file = SourceFile.virtual("<completions>", expr, maybeIncomplete = true)
232+
val unit = CompilationUnit(file)(using state.context)
233+
unit.tpdTree = tree
234+
given Context = state.context.fresh.setCompilationUnit(unit)
235+
val srcPos = SourcePosition(file, Span(cursor))
236+
val (_, completions) = Completion.completions(srcPos)
237+
completions.map(_.label).distinct.map(makeCandidate)
238+
}
239+
.getOrElse(Nil)
240+
end completions
235241

236242
private def interpret(res: ParseResult)(implicit state: State): State = {
237243
res match {

compiler/test/dotty/tools/repl/TabcompleteTests.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,37 @@ class TabcompleteTests extends ReplTest {
195195
|Foo.`bac"""stripMargin))
196196
}
197197

198+
@Test def backtickedImport = initially {
199+
assertEquals(
200+
List(
201+
"`scalaUtilChainingOps`",
202+
"`synchronized`"
203+
),
204+
tabComplete("import scala.util.chaining.`s"))
205+
}
206+
207+
@Test def commands = initially {
208+
assertEquals(
209+
List(
210+
":doc",
211+
":exit",
212+
":help",
213+
":imports",
214+
":load",
215+
":quit",
216+
":reset",
217+
":settings",
218+
":type"
219+
),
220+
tabComplete(":")
221+
)
222+
}
223+
224+
@Test def commandPreface = initially {
225+
// This looks odd, but if we return :doc here it will result in ::doc in the REPL
226+
assertEquals(
227+
List(":doc"),
228+
tabComplete(":d")
229+
)
230+
}
198231
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ A usage of a variadic extractor is irrefutable if one of the following condition
9494
## Boolean Match
9595

9696
- `U =:= Boolean`
97-
- Pattern-matching on exactly `0` pattern
97+
- Pattern-matching on exactly `0` patterns
9898

9999
For example:
100100

docs/_docs/reference/contextual/derivation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ given eqProduct[A](using inst: K0.ProductInstances[Eq, A]): Eq[A] with
330330
)
331331

332332
inline def derived[A](using gen: K0.Generic[A]): Eq[A] =
333-
gen.derive(eqSum, eqProduct)
333+
gen.derive(eqProduct, eqSum)
334334
```
335335

336336
The framework described here enables all three of these approaches without mandating any of them.

docs/_docs/reference/contextual/using-clauses.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def maximum[T](xs: List[T])(using Ord[T]): T =
4343
xs.reduceLeft(max)
4444
```
4545

46-
`maximum` takes a context parameter of type `Ord` only to pass it on as an
46+
`maximum` takes a context parameter of type `Ord[T]` only to pass it on as an
4747
inferred argument to `max`. The name of the parameter is left out.
4848

4949
Generally, context parameters may be defined either as a full parameter list `(p_1: T_1, ..., p_n: T_n)` or just as a sequence of types `T_1, ..., T_n`. Vararg parameters are not supported in `using` clauses.

docs/_docs/reference/metaprogramming/staging.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impose the following restrictions on the use of splices.
6060
The framework as discussed so far allows code to be staged, i.e. be prepared
6161
to be executed at a later stage. To run that code, there is another method
6262
in class `Expr` called `run`. Note that `$` and `run` both map from `Expr[T]`
63-
to `T` but only `$` is subject to the PCP, whereas `run` is just a normal method.
63+
to `T` but only `$` is subject to the [PCP](./macros.md#the-phase-consistency-principle), whereas `run` is just a normal method.
6464
`scala.quoted.staging.run` provides a `Quotes` that can be used to show the expression in its scope.
6565
On the other hand `scala.quoted.staging.withQuotes` provides a `Quotes` without evaluating the expression.
6666

docs/_docs/reference/new-types/match-types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use of the match type as the return type):
6767
```scala
6868
def leafElem[X](x: X): LeafElem[X] = x match
6969
case x: String => x.charAt(0)
70-
case x: Array[t] => leafElem(x(9))
70+
case x: Array[t] => leafElem(x(0))
7171
case x: Iterable[t] => leafElem(x.head)
7272
case x: AnyVal => x
7373
```

docs/_docs/reference/new-types/union-types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ scala> val name = UserName("Eve")
3232
val name: UserName = UserName(Eve)
3333

3434
scala> if true then name else password
35-
val res2: Object & Product = UserName(Eve)
35+
val res2: Object = UserName(Eve)
3636

3737
scala> val either: Password | UserName = if true then name else password
3838
val either: Password | UserName = UserName(Eve)

docs/_docs/reference/other-new-features/matchable.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@ For instance, consider the definitions
119119

120120
```scala
121121
opaque type Meter = Double
122-
def Meter(x: Double) = x
122+
def Meter(x: Double): Meter = x
123123

124124
opaque type Second = Double
125-
def Second(x: Double) = x
125+
def Second(x: Double): Second = x
126126
```
127127

128128
Here, universal `equals` will return true for
@@ -134,6 +134,7 @@ Here, universal `equals` will return true for
134134
even though this is clearly false mathematically. With [multiversal equality](../contextual/multiversal-equality.md) one can mitigate that problem somewhat by turning
135135

136136
```scala
137+
import scala.language.strictEquality
137138
Meter(10) == Second(10)
138139
```
139140

docs/_docs/reference/other-new-features/transparent-traits.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ appear in the inferred type.
4242

4343
The traits [`scala.Product`](https://scala-lang.org/api/3.x/scala/Product.html), [`java.io.Serializable`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html) and [`java.lang.Comparable`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Comparable.html)
4444
are treated automatically as transparent. Other traits are turned into transparent traits using the modifier `transparent`. Scala 2 traits can also be made transparent
45-
by adding a [`@transparentTrait`](https://scala-lang.org/api/3.x/scala/annotation/transparentTrait.html) annotation. This annotation is defined in [`scala.annotation`](https://scala-lang.org/api/3.x/scala/annotation.html). It will be deprecated and phased out once Scala 2/3 interopability is no longer needed.
45+
by adding a [`@transparentTrait`](https://scala-lang.org/api/3.x/scala/annotation/transparentTrait.html) annotation. This annotation is defined in [`scala.annotation`](https://scala-lang.org/api/3.x/scala/annotation.html). It will be deprecated and phased out once Scala 2/3 interoperability is no longer needed.
4646

4747
Typically, transparent traits are traits
4848
that influence the implementation of inheriting classes and traits that are not usually used as types by themselves. Two examples from the standard collection library are:

docs/_docs/reference/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ given if implicit import lazy match new
115115
null object override package private protected return
116116
sealed super then throw trait true try
117117
type val var while with yield
118-
: = <- => <: :> #
118+
: = <- => <: >: #
119119
@ =>> ?=>
120120
```
121121

0 commit comments

Comments
 (0)