Skip to content

Commit 99548bd

Browse files
authored
Merge pull request #9949 from dotty-staging/change-given-wildcard-import
Change wildcard given selectors
2 parents 63dd4f9 + f48b816 commit 99548bd

File tree

20 files changed

+51
-41
lines changed

20 files changed

+51
-41
lines changed

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

+9-4
Original file line numberDiff line numberDiff line change
@@ -3094,16 +3094,18 @@ object Parsers {
30943094
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
30953095
* ImportSpec ::= id
30963096
* | ‘_’
3097+
* | ‘given’
30973098
* | ‘{’ ImportSelectors) ‘}’
30983099
*/
30993100
def importExpr(mkTree: ImportConstr): () => Tree = {
31003101

31013102
/** '_' */
31023103
def wildcardSelectorId() = atSpan(in.skipToken()) { Ident(nme.WILDCARD) }
3104+
def givenSelectorId(start: Offset) = atSpan(start) { Ident(nme.EMPTY) }
31033105

31043106
/** ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
31053107
* | WildCardSelector {‘,’ WildCardSelector}
3106-
* WildCardSelector ::= ‘given’ (‘_' | InfixType)
3108+
* WildCardSelector ::= ‘given’ [InfixType]
31073109
* | ‘_'
31083110
*/
31093111
def importSelectors(idOK: Boolean): List[ImportSelector] =
@@ -3114,12 +3116,13 @@ object Parsers {
31143116
ImportSelector(wildcardSelectorId())
31153117
case GIVEN =>
31163118
val start = in.skipToken()
3117-
def givenSelector() = atSpan(start) { Ident(nme.EMPTY) }
31183119
if in.token == USCORE then
31193120
in.nextToken()
3120-
ImportSelector(givenSelector()) // Let the selector span all of `given _`; needed for -Ytest-pickler
3121+
ImportSelector(givenSelectorId(start)) // Let the selector span all of `given _`; needed for -Ytest-pickler
3122+
else if canStartTypeTokens.contains(in.token) then
3123+
ImportSelector(givenSelectorId(start), bound = rejectWildcardType(infixType()))
31213124
else
3122-
ImportSelector(givenSelector(), bound = infixType())
3125+
ImportSelector(givenSelectorId(start))
31233126
case _ =>
31243127
val from = termIdent()
31253128
if !idOK then syntaxError(i"named imports cannot follow wildcard imports")
@@ -3143,6 +3146,8 @@ object Parsers {
31433146
in.token match
31443147
case USCORE =>
31453148
mkTree(qual, ImportSelector(wildcardSelectorId()) :: Nil)
3149+
case GIVEN =>
3150+
mkTree(qual, ImportSelector(givenSelectorId(in.skipToken())) :: Nil)
31463151
case LBRACE =>
31473152
mkTree(qual, inBraces(importSelectors(idOK = true)))
31483153
case _ =>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ object Tokens extends TokensCommon {
261261
final val canStartStatTokens3: TokenSet = canStartExprTokens3 | mustStartStatTokens | BitSet(
262262
AT, CASE)
263263

264-
final val canEndStatTokens: TokenSet = atomicExprTokens | BitSet(TYPE, RPAREN, RBRACE, RBRACKET, OUTDENT)
264+
final val canEndStatTokens: TokenSet = atomicExprTokens | BitSet(TYPE, GIVEN, RPAREN, RBRACE, RBRACKET, OUTDENT)
265265

266266
/** Tokens that stop a lookahead scan search for a `<-`, `then`, or `do`.
267267
* Used for disambiguating between old and new syntax.

docs/docs/internals/syntax.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,11 @@ Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
348348
ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec Import(expr, sels)
349349
ImportSpec ::= id
350350
| ‘_’
351+
| ‘given’
351352
| ‘{’ ImportSelectors) ‘}’
352353
ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
353354
| WildCardSelector {‘,’ WildCardSelector}
354-
WildCardSelector ::= ‘given’ (‘_' | InfixType)
355+
WildCardSelector ::= ‘given’ [InfixType]
355356
| ‘_'
356357
Export ::= ‘export’ [‘given’] ImportExpr {‘,’ ImportExpr}
357358

docs/docs/reference/contextual/given-imports.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ object A {
1414

1515
object B {
1616
import A._
17-
import A.{given _}
17+
import A.given
1818
}
1919
```
2020

2121
In the code above, the `import A._` clause of object `B` will import all members
22-
of `A` _except_ the given instance `tc`. Conversely, the second import `import A.{given _}` will import _only_ that given instance.
22+
of `A` _except_ the given instance `tc`. Conversely, the second import `import A.given` will import _only_ that given instance.
2323
The two import clauses can also be merged into one:
2424

2525
```scala
2626
object B {
27-
import A.{given _, _}
27+
import A.{given, _}
2828
}
2929
```
3030

3131
Generally, a normal wildcard selector `_` brings all definitions other than givens or extensions into scope
32-
whereas a `given _` selector brings all givens (including those resulting from extensions) into scope.
32+
whereas a `given` selector brings all givens (including those resulting from extensions) into scope.
3333

3434
There are two main benefits arising from these rules:
3535

@@ -106,13 +106,13 @@ normal imports to givens and given imports.
106106
The following modifications avoid this hurdle to migration.
107107

108108
1. A `given` import selector also brings old style implicits into scope. So, in Scala 3.0
109-
an old-style implicit definition can be brought into scope either by a `_` or a `given _` wildcard selector.
109+
an old-style implicit definition can be brought into scope either by a `_` or a `given` wildcard selector.
110110

111111
2. In Scala 3.1, old-style implicits accessed through a `_` wildcard import will give a deprecation warning.
112112

113113
3. In some version after 3.1, old-style implicits accessed through a `_` wildcard import will give a compiler error.
114114

115-
These rules mean that library users can use `given _` selectors to access old-style implicits in Scala 3.0,
115+
These rules mean that library users can use `given` selectors to access old-style implicits in Scala 3.0,
116116
and will be gently nudged and then forced to do so in later versions. Libraries can then switch to
117117
given instances once their user base has migrated.
118118

@@ -123,10 +123,11 @@ Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
123123
ImportExpr ::= StableId ‘.’ ImportSpec
124124
ImportSpec ::= id
125125
| ‘_’
126+
| ‘given’
126127
| ‘{’ ImportSelectors) ‘}’
127128
ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
128129
| WildCardSelector {‘,’ WildCardSelector}
129130
WildCardSelector ::= ‘_'
130-
| ‘given’ (‘_' | InfixType)
131+
| ‘given’ [InfixType]
131132
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
132133
```

tests/disabled/pos-macros/i7853/SummonJsonEncoderTest_2.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import scala.deriving._
22
import scala.quoted._
3-
import JsonEncoder.{given _, _}
3+
import JsonEncoder.{given, _}
44

55
object SummonJsonEncoderTest {
66

tests/neg-custom-args/impl-conv/B.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package implConv
22

33
object B {
4-
import A.{_, given _}
4+
import A.{_, given}
55

66
"".foo
77

tests/neg-custom-args/implicit-conversions.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ object D {
2121
}
2222

2323
object Test {
24-
import D.{given _}
24+
import D.given
2525

2626
val x1: A = new B // error under -Xfatal-warnings -feature
2727
val x2: B = new A // error under -Xfatal-warnings -feature

tests/neg-macros/i7048e.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ abstract class Test {
1313

1414
{
1515
val t: Test = this
16-
import t.{given _}
16+
import t.given
1717
println(summon[Type[t.T]].show)
1818
// val r = '{Option.empty[t.T]} // access to value t from wrong staging level
1919
val r2 = '{Option.empty[${t.T}]} // works

tests/neg/import-implied.scala renamed to tests/neg/import-given.scala

+5-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@ object C {
1616
foo(using tc) // ok
1717
}
1818
object D {
19-
import A.{foo, given _}
19+
import A.{foo, given}
2020
foo // ok
2121
foo(using tc) // ok
2222
}
2323
object E {
24-
import A.{_, given _}
24+
import A.{_, given}
2525
foo // ok
2626
foo(using tc) // ok
2727
}
28+
object F:
29+
import A.{given ?} // error: unbound wildcard type
30+

tests/pos-macros/i7011/Macros_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import scala.quoted._
33
inline def mcr(body: => Any): Unit = ${mcrImpl('body)}
44

55
def mcrImpl[T](body: Expr[Any])(using ctx: QuoteContext) : Expr[Any] = {
6-
import ctx.tasty.{_, given _}
6+
import ctx.tasty.{_, given}
77

88
val bTree = body.unseal
99
val under = bTree.underlyingArgument

tests/pos-macros/i7048e.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ abstract class Test {
1313

1414
{
1515
val t: Test = this
16-
import t.{given _}
16+
import t.given
1717
println(summon[Type[t.T]].show)
1818
// val r = '{Option.empty[t.T]} // access to value t from wrong staging level
1919
val r2 = '{Option.empty[${t.T}]}

tests/pos-macros/i8651b.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object Macros {
99
inline def coroutine[T](inline body: Any): Coroutine[T] = ${ coroutineImpl('{body}) }
1010

1111
def coroutineImpl[T: Type](expr: Expr[_ <: Any])(implicit qtx: QuoteContext): Expr[Coroutine[T]] = {
12-
import qtx.tasty.{_, given _}
12+
import qtx.tasty.{_, given}
1313

1414
'{
1515
new Coroutine[T] {

tests/pos-special/fatal-warnings/tasty-parent-unapply.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ object Macros {
66

77

88
def impl(reflect: Reflection): Unit = {
9-
import reflect.{_, given _}
9+
import reflect.{_, given}
1010

1111
def foo(tree: Tree, term: Term, typeTree: TypeTree, parent: Tree) = {
1212

tests/pos/i5978.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ package p1 {
2121

2222
object Testcase {
2323
def main(args: Array[String]): Unit = {
24-
import TextParser.{given _, _}
24+
import TextParser.{given, _}
2525

2626
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
2727
val tp_i = summon[TokenParser[Char, Position[CharSequence]]]
@@ -45,7 +45,7 @@ package p2 {
4545

4646
object Testcase {
4747
def main(args: Array[String]): Unit = {
48-
import TextParser.{given _, _}
48+
import TextParser.{given, _}
4949

5050
val tp_v: TokenParser[Char, Position[CharSequence]] = TextParser.TP
5151
val tp_i = summon[TokenParser[Char, Position[CharSequence]]]
@@ -63,7 +63,7 @@ package p3 {
6363

6464
object Testcase {
6565
def main(args: Array[String]): Unit = {
66-
import TextParser.{_, given _}
66+
import TextParser.{_, given}
6767

6868
val co_i: Conversion[Char, Position[CharSequence]] = summon[Conversion[Char, Position[CharSequence]]]
6969

tests/pos/i7532.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Tasty {
1212

1313
object Foo {
1414
def impl(using tasty: Tasty) : Unit = {
15-
import tasty.{_, given _}
15+
import tasty.{_, given}
1616
val Select() = (??? : Term)
1717
}
1818
}

tests/run-custom-args/Yretain-trees/tasty-extractors-owners/quoted_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object Macros {
1818
}
1919

2020
class MyTraverser[R <: scala.tasty.Reflection & Singleton](val reflect: R)(buff: StringBuilder) extends scala.tasty.reflect.TreeTraverser {
21-
import reflect.{given _, _}
21+
import reflect.{given, _}
2222
override def traverseTree(tree: Tree)(implicit ctx: Context): Unit = {
2323
tree match {
2424
case tree @ DefDef(name, _, _, _, _) =>

tests/run-macros/i8007/Test_4.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ enum OptInv[+T] {
1717

1818
@main def Test() = {
1919
import Opt._
20-
import Eq.{given _, _}
20+
import Eq.{given, _}
2121

2222
val t1 = test1(Person("Test", 23))
2323
println(t1)

tests/run-macros/tasty-tree-map/quoted_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ object Macros {
55
implicit inline def identityMaped[T](x: => T): T = ${ impl('x) }
66

77
def impl[T: Type](x: Expr[T])(using qctx: QuoteContext) : Expr[T] = {
8-
import qctx.tasty.{_, given _} // FIXME: #8919
8+
import qctx.tasty.{_, given} // FIXME: #8919
99
val identityMap = new TreeMap { }
1010
val transformed = identityMap.transformTerm(x.unseal).seal.cast[T]
1111
transformed

tests/run/exports.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object Test extends App {
1818

1919
object Copier {
2020
val printer = new Printer
21-
export printer.{given _, _}
21+
export printer.{given, _}
2222
export Scanner.{scan => scanIt, _}
2323

2424
val config2 = summon[Config]

tests/run/implied-priority.scala

+10-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ object NormalImplicits extends LowPriorityImplicits {
1919
}
2020

2121
def test1 = {
22-
import NormalImplicits.{given _}
22+
import NormalImplicits.given
2323
assert(summon[E[String]].str == "low") // No Arg available, so only t1 applies
2424

2525
{ given Arg[String]
@@ -43,7 +43,7 @@ object Impl2 {
4343
}
4444

4545
def test2 = {
46-
import Impl2.{given _}
46+
import Impl2.given
4747
assert(summon[E[String]].str == "low") // No Arg available, so only t1 applies
4848

4949
{ given Arg[String]
@@ -64,8 +64,8 @@ object Impl2a {
6464
}
6565

6666
def test2a = {
67-
import Impl2.{given _}
68-
import Impl2a.{given _}
67+
import Impl2.given
68+
import Impl2a.given
6969

7070
given Arg[String]
7171
assert(summon[E[String]].str == "hi")
@@ -85,11 +85,11 @@ object Override {
8585
}
8686

8787
def test3 = {
88-
import Impl3.{given _}
88+
import Impl3.given
8989
assert(summon[E[String]].str == "low") // only t1 is available
9090

91-
{ import Override.{given _}
92-
import Impl3.{given _}
91+
{ import Override.given
92+
import Impl3.given
9393
assert(summon[E[String]].str == "hi") // `over` takes priority since its result type is a subtype of t1's.
9494
}
9595
}
@@ -111,7 +111,7 @@ object fallback4 {
111111
}
112112

113113
def test4 = {
114-
import Impl4.{given _}
114+
import Impl4.given
115115
import fallback4._
116116
assert(withFallback[String].str == "string") // t1 is applicable
117117
assert(withFallback[Int].str == "fallback") // No applicable instances, pick the default
@@ -138,8 +138,8 @@ object fallback5 {
138138
}
139139

140140
def test5 = {
141-
import Impl4.{given _}
142-
import fallback5.{given _}
141+
import Impl4.given
142+
import fallback5.given
143143

144144
// All inferred terms go through the given instance in fallback5.
145145
// They differ in what implicit argument is synthesized for that instance.

0 commit comments

Comments
 (0)