Skip to content

Commit ed5ecac

Browse files
authored
Merge pull request #11244 from dotty-staging/change-imports
Allow new import syntax
2 parents bea5619 + 068ad0a commit ed5ecac

File tree

1,555 files changed

+2586
-2429
lines changed

Some content is hidden

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

1,555 files changed

+2586
-2429
lines changed

bench/tests/Vector.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ package immutable
1212

1313
import scala.annotation.unchecked.uncheckedVariance
1414
import scala.compat.Platform
15-
import scala.collection.generic._
15+
import scala.collection.generic.*
1616
import scala.collection.mutable.Builder
1717
import compiletime.uninitialized
1818

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object PowerInlined {
2-
import PowerMacro._
2+
import PowerMacro.*
33

44
power(1, 5.0) // 1 quotes to unpickle
55
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object PowerInlined {
2-
import PowerMacro._
2+
import PowerMacro.*
33

44
power(1, 5.0) // 1 quotes to unpickle
55
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
179179
case _ => false
180180
}
181181

182-
/** Is this argument node of the form <expr> : _*, or is it a reference to
182+
/** Is this argument node of the form <expr> *, or is it a reference to
183183
* such an argument ? The latter case can happen when an argument is lifted.
184184
*/
185185
def isWildcardStarArg(tree: Tree)(using Context): Boolean = unbind(tree) match {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,7 @@ object Trees {
10271027
type Template = Trees.Template[T]
10281028
type Import = Trees.Import[T]
10291029
type Export = Trees.Export[T]
1030+
type ImportOrExport = Trees.ImportOrExport[T]
10301031
type PackageDef = Trees.PackageDef[T]
10311032
type Annotated = Trees.Annotated[T]
10321033
type Thicket = Trees.Thicket[T]

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

Lines changed: 83 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3066,8 +3066,8 @@ object Parsers {
30663066

30673067
type ImportConstr = (Tree, List[ImportSelector]) => Tree
30683068

3069-
/** Import ::= `import' [`given'] [ImportExpr {`,' ImportExpr}
3070-
* Export ::= `export' [`given'] [ImportExpr {`,' ImportExpr}
3069+
/** Import ::= `import' ImportExpr {‘,’ ImportExpr}
3070+
* Export ::= `export' ImportExpr {‘,’ ImportExpr}
30713071
*/
30723072
def importClause(leading: Token, mkTree: ImportConstr): List[Tree] = {
30733073
val offset = accept(leading)
@@ -3097,48 +3097,62 @@ object Parsers {
30973097
ctx.compilationUnit.sourceVersion = Some(SourceVersion.valueOf(imported.toString))
30983098
Import(tree, selectors)
30993099

3100-
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
3101-
* ImportSpec ::= id
3102-
* | ‘_’
3103-
* | ‘given’
3104-
* | ‘{’ ImportSelectors) ‘}’
3105-
*/
3106-
def importExpr(mkTree: ImportConstr): () => Tree = {
3107-
3108-
/** '_' */
3109-
def wildcardSelectorId() = atSpan(in.skipToken()) { Ident(nme.WILDCARD) }
3110-
def givenSelectorId(start: Offset) = atSpan(start) { Ident(nme.EMPTY) }
3100+
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec
3101+
* | SimpleRef ‘as’ id
3102+
* ImportSpec ::= NamedSelector
3103+
* | WildcardSelector
3104+
* | ‘{’ ImportSelectors ‘}’
3105+
* ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]
3106+
* | WildCardSelector {‘,’ WildCardSelector}
3107+
* NamedSelector ::= id [‘as’ (id | ‘_’)]
3108+
* WildCardSelector ::= ‘*' | ‘given’ [InfixType]
3109+
*/
3110+
def importExpr(mkTree: ImportConstr): () => Tree =
3111+
3112+
/** ‘*' | ‘_' */
3113+
def wildcardSelector() =
3114+
if in.token == USCORE && sourceVersion.isAtLeast(`3.1`) then
3115+
report.errorOrMigrationWarning(
3116+
em"`_` is no longer supported for a wildcard import; use `*` instead${rewriteNotice("3.1")}",
3117+
in.sourcePos())
3118+
patch(source, Span(in.offset, in.offset + 1), "*")
3119+
ImportSelector(atSpan(in.skipToken()) { Ident(nme.WILDCARD) })
3120+
3121+
/** 'given [InfixType]' */
3122+
def givenSelector() =
3123+
ImportSelector(
3124+
atSpan(in.skipToken()) { Ident(nme.EMPTY) },
3125+
bound =
3126+
if canStartTypeTokens.contains(in.token) then rejectWildcardType(infixType())
3127+
else EmptyTree)
3128+
3129+
/** id [‘as’ (id | ‘_’) */
3130+
def namedSelector(from: Ident) =
3131+
if in.token == ARROW || isIdent(nme.as) then
3132+
if in.token == ARROW && sourceVersion.isAtLeast(`3.1`) then
3133+
report.errorOrMigrationWarning(
3134+
em"The import renaming `a => b` is no longer supported ; use `a as b` instead${rewriteNotice("3.1")}",
3135+
in.sourcePos())
3136+
patch(source, Span(in.offset, in.offset + 2),
3137+
if testChar(in.offset - 1, ' ') && testChar(in.offset + 2, ' ') then "as"
3138+
else " as ")
3139+
atSpan(startOffset(from), in.skipToken()) {
3140+
val to = if in.token == USCORE then wildcardIdent() else termIdent()
3141+
ImportSelector(from, if to.name == nme.ERROR then EmptyTree else to)
3142+
}
3143+
else ImportSelector(from)
31113144

3112-
/** ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
3113-
* | WildCardSelector {‘,’ WildCardSelector}
3114-
* WildCardSelector ::= ‘given’ [InfixType]
3115-
* | ‘_'
3116-
*/
31173145
def importSelectors(idOK: Boolean): List[ImportSelector] =
3118-
val isWildcard = in.token == USCORE || in.token == GIVEN
3146+
val isWildcard = in.token == USCORE || in.token == GIVEN || isIdent(nme.raw.STAR)
31193147
val selector = atSpan(in.offset) {
31203148
in.token match
3121-
case USCORE =>
3122-
ImportSelector(wildcardSelectorId())
3123-
case GIVEN =>
3124-
val start = in.skipToken()
3125-
if in.token == USCORE then
3126-
deprecationWarning(em"`given _` is deprecated in imports; replace with just `given`", start)
3127-
in.nextToken()
3128-
ImportSelector(givenSelectorId(start)) // Let the selector span all of `given`; needed for -Ytest-pickler
3129-
else if canStartTypeTokens.contains(in.token) then
3130-
ImportSelector(givenSelectorId(start), bound = rejectWildcardType(infixType()))
3131-
else
3132-
ImportSelector(givenSelectorId(start))
3149+
case USCORE => wildcardSelector()
3150+
case GIVEN => givenSelector()
31333151
case _ =>
3134-
val from = termIdent()
3135-
if !idOK then syntaxError(i"named imports cannot follow wildcard imports")
3136-
if in.token == ARROW then
3137-
atSpan(startOffset(from), in.skipToken()) {
3138-
val to = if in.token == USCORE then wildcardIdent() else termIdent()
3139-
ImportSelector(from, if to.name == nme.ERROR then EmptyTree else to)
3140-
}
3141-
else ImportSelector(from)
3152+
if isIdent(nme.raw.STAR) then wildcardSelector()
3153+
else
3154+
if !idOK then syntaxError(i"named imports cannot follow wildcard imports")
3155+
namedSelector(termIdent())
31423156
}
31433157
val rest =
31443158
if in.token == COMMA then
@@ -3149,26 +3163,36 @@ object Parsers {
31493163
selector :: rest
31503164

31513165
def importSelection(qual: Tree): Tree =
3152-
accept(DOT)
3153-
in.token match
3154-
case USCORE =>
3155-
mkTree(qual, ImportSelector(wildcardSelectorId()) :: Nil)
3156-
case GIVEN =>
3157-
mkTree(qual, ImportSelector(givenSelectorId(in.skipToken())) :: Nil)
3158-
case LBRACE =>
3159-
mkTree(qual, inBraces(importSelectors(idOK = true)))
3160-
case _ =>
3161-
val start = in.offset
3162-
val name = ident()
3163-
if in.token == DOT then
3164-
importSelection(atSpan(startOffset(qual), start) { Select(qual, name) })
3165-
else
3166-
atSpan(startOffset(qual)) {
3167-
mkTree(qual, ImportSelector(atSpan(start) { Ident(name) }) :: Nil)
3168-
}
3169-
3170-
() => importSelection(simpleRef())
3171-
}
3166+
if in.isIdent(nme.as) && qual.isInstanceOf[RefTree] then
3167+
qual match
3168+
case Select(qual1, name) =>
3169+
val from = Ident(name).withSpan(Span(qual.span.point, qual.span.end, 0))
3170+
mkTree(qual1, namedSelector(from) :: Nil)
3171+
case qual: Ident =>
3172+
mkTree(EmptyTree, namedSelector(qual) :: Nil)
3173+
else
3174+
accept(DOT)
3175+
in.token match
3176+
case USCORE =>
3177+
mkTree(qual, wildcardSelector() :: Nil)
3178+
case GIVEN =>
3179+
mkTree(qual, givenSelector() :: Nil)
3180+
case LBRACE =>
3181+
mkTree(qual, inBraces(importSelectors(idOK = true)))
3182+
case _ =>
3183+
if isIdent(nme.raw.STAR) then
3184+
mkTree(qual, wildcardSelector() :: Nil)
3185+
else
3186+
val start = in.offset
3187+
val name = ident()
3188+
if in.token == DOT then
3189+
importSelection(atSpan(startOffset(qual), start) { Select(qual, name) })
3190+
else
3191+
mkTree(qual, namedSelector(atSpan(start) { Ident(name) }) :: Nil)
3192+
end importSelection
3193+
3194+
() => atSpan(in.offset) { importSelection(simpleRef()) }
3195+
end importExpr
31723196

31733197
/** Def ::= val PatDef
31743198
* | var VarDef

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,13 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
340340

341341
def selectorText(sel: untpd.ImportSelector): Text =
342342
val id: Text =
343-
if sel.isGiven then keywordText("given") else toText(sel.imported)
343+
if sel.isGiven then keywordText("given")
344+
else sel.imported.name match
345+
case nme.WILDCARD => "*"
346+
case nme.raw.STAR => "`*`"
347+
case name => toText(name)
344348
val rename: Text =
345-
if sel.renamed.isEmpty then "" else Str(" => ") ~ toText(sel.renamed)
349+
if sel.renamed.isEmpty then "" else Str(" as ") ~ toText(sel.renamed)
346350
val bound: Text =
347351
if sel.bound.isEmpty then ""
348352
else if sel.isGiven then Str(" ") ~ toText(sel.bound)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase =>
150150
}
151151

152152
override def transformOther(tree: Tree)(using Context): Tree = tree match {
153-
case tree: ImportOrExport[_] => EmptyTree
153+
case tree: ImportOrExport => EmptyTree
154154
case tree: NamedArg => transformAllDeep(tree.arg)
155155
case tree => if (tree.isType) toTypeTree(tree) else tree
156156
}

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ class Namer { typer: Typer =>
693693
// make sure testing contexts are not captured by completers
694694
assert(!ictx.reporter.isInstanceOf[ExploringReporter])
695695

696-
protected def typeSig(sym: Symbol): Type = original match {
696+
protected def typeSig(sym: Symbol): Type = original match
697697
case original: ValDef =>
698698
if (sym.is(Module)) moduleValSig(sym)
699699
else valOrDefDefSig(original, sym, Nil, identity)(using localContext(sym).setNewScope)
@@ -702,16 +702,12 @@ class Namer { typer: Typer =>
702702
nestedTyper(sym) = typer1
703703
typer1.defDefSig(original, sym)(using localContext(sym).setTyper(typer1))
704704
case imp: Import =>
705-
try {
706-
val expr1 = typedAheadExpr(imp.expr, AnySelectionProto)
705+
try
706+
val expr1 = typedImportQualifier(imp, typedAheadExpr)
707707
ImportType(expr1)
708-
}
709-
catch {
710-
case ex: CyclicReference =>
711-
typr.println(s"error while completing ${imp.expr}")
712-
throw ex
713-
}
714-
}
708+
catch case ex: CyclicReference =>
709+
typr.println(s"error while completing ${imp.expr}")
710+
throw ex
715711

716712
final override def complete(denot: SymDenotation)(using Context): Unit = {
717713
if (Config.showCompletions && ctx.typerState != creationContext.typerState) {
@@ -987,6 +983,10 @@ class Namer { typer: Typer =>
987983
def exportForwarders(exp: Export): List[tpd.MemberDef] = {
988984
val buf = new mutable.ListBuffer[tpd.MemberDef]
989985
val Export(expr, selectors) = exp
986+
if expr.isEmpty then
987+
report.error(em"Export selector must have prefix and `.`", exp.srcPos)
988+
return Nil
989+
990990
val path = typedAheadExpr(expr, AnySelectionProto)
991991
checkLegalExportPath(path, selectors)
992992
lazy val wildcardBound = importBound(selectors, isGiven = false)

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2338,19 +2338,36 @@ class Typer extends Namer
23382338
.asInstanceOf[untpd.ImportSelector]
23392339
}
23402340

2341-
def typedImport(imp: untpd.Import, sym: Symbol)(using Context): Import = {
2342-
val expr1 = typedExpr(imp.expr, AnySelectionProto)
2341+
def typedImportQualifier(imp: untpd.Import, typd: (untpd.Tree, Type) => Tree)(using Context): Tree =
2342+
if imp.expr == untpd.EmptyTree then
2343+
assert(imp.selectors.length == 1, imp)
2344+
val from = imp.selectors.head.imported
2345+
val sel = tryAlternatively
2346+
(typedIdent(from, WildcardType))
2347+
(typedIdent(cpy.Ident(from)(from.name.toTypeName), WildcardType))
2348+
2349+
sel.tpe match
2350+
case TermRef(prefix: SingletonType, _) =>
2351+
singleton(prefix).withSpan(from.span)
2352+
case TypeRef(prefix: SingletonType, _) =>
2353+
singleton(prefix).withSpan(from.span)
2354+
case _ =>
2355+
errorTree(from,
2356+
em"""Illegal import selector: $from
2357+
|The selector is not a member of an object or package.""")
2358+
else typd(imp.expr, AnySelectionProto)
2359+
2360+
def typedImport(imp: untpd.Import, sym: Symbol)(using Context): Import =
2361+
val expr1 = typedImportQualifier(imp, typedExpr)
23432362
checkLegalImportPath(expr1)
23442363
val selectors1 = typedSelectors(imp.selectors)
23452364
assignType(cpy.Import(imp)(expr1, selectors1), sym)
2346-
}
23472365

2348-
def typedExport(exp: untpd.Export)(using Context): Export = {
2366+
def typedExport(exp: untpd.Export)(using Context): Export =
23492367
val expr1 = typedExpr(exp.expr, AnySelectionProto)
23502368
// already called `checkLegalExportPath` in Namer
23512369
val selectors1 = typedSelectors(exp.selectors)
23522370
assignType(cpy.Export(exp)(expr1, selectors1))
2353-
}
23542371

23552372
def typedPackageDef(tree: untpd.PackageDef)(using Context): Tree =
23562373
val pid1 = withMode(Mode.InPackageClauseName)(typedExpr(tree.pid, AnySelectionProto))

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class CompilationTests {
6767

6868
aggregateTests(
6969
compileFile("tests/rewrites/rewrites.scala", scala2CompatMode.and("-rewrite", "-indent")),
70+
compileFile("tests/rewrites/rewrites3x.scala", defaultOptions.and("-rewrite", "-source", "3.1-migration")),
7071
compileFile("tests/rewrites/i8982.scala", defaultOptions.and("-indent", "-rewrite")),
7172
compileFile("tests/rewrites/i9632.scala", defaultOptions.and("-indent", "-rewrite"))
7273
).checkRewrites()

docs/docs/contributing/workflow.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type stealer:
4545
```bash
4646
$ sbt
4747
> repl
48-
scala> import dotty.tools.DottyTypeStealer._; import dotty.tools.dotc.core._; import Contexts._,Types._
48+
scala> import dotty.tools.DottyTypeStealer.*; import dotty.tools.dotc.core.*; import Contexts.*,Types.*
4949
```
5050

5151
Now, you can define types and access their representation. For example:

docs/docs/internals/syntax.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ type val var while with yield
120120
### Soft keywords
121121
122122
```
123-
derives end extension infix inline opaque open transparent using | * + -
123+
as derives end extension infix inline opaque open transparent using | * + -
124124
```
125125
126126
See the [separate section on soft keywords](./soft-modifier.md) for additional
@@ -258,8 +258,7 @@ ArgumentExprs ::= ParArgumentExprs
258258
BlockExpr ::= <<< (CaseClauses | Block) >>>
259259
Block ::= {BlockStat semi} [BlockResult] Block(stats, expr?)
260260
BlockStat ::= Import
261-
| {Annotation {nl}} [‘implicit’ | ‘lazy’] Def
262-
| {Annotation {nl}} {LocalModifier} TmplDef
261+
| {Annotation {nl}} {LocalModifier} Def
263262
| Extension
264263
| Expr1
265264
| EndMarker
@@ -353,16 +352,16 @@ AccessQualifier ::= ‘[’ id ‘]’
353352
Annotation ::= ‘@’ SimpleType1 {ParArgumentExprs} Apply(tpe, args)
354353
355354
Import ::= ‘import’ ImportExpr {‘,’ ImportExpr}
355+
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
356356
ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec Import(expr, sels)
357-
ImportSpec ::= id
358-
| ‘_’
359-
| ‘given’
357+
| SimpleRef ‘as’ id Import(EmptyTree, ImportSelector(ref, id))
358+
ImportSpec ::= NamedSelector
359+
| WildcardSelector
360360
| ‘{’ ImportSelectors) ‘}’
361-
ImportSelectors ::= id [‘=>’ id | ‘=>’ ‘_’] [‘,’ ImportSelectors]
361+
NamedSelector ::= id [‘as’ (id | ‘_’)]
362+
WildCardSelector ::= ‘*' | ‘given’ [InfixType]
363+
ImportSelectors ::= NamedSelector [‘,’ ImportSelectors]
362364
| WildCardSelector {‘,’ WildCardSelector}
363-
WildCardSelector ::= ‘given’ [InfixType]
364-
| ‘_'
365-
Export ::= ‘export’ ImportExpr {‘,’ ImportExpr}
366365
367366
EndMarker ::= ‘end’ EndMarkerTag -- when followed by EOL
368367
EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ | ‘try’

0 commit comments

Comments
 (0)