Skip to content

Commit 86e36e7

Browse files
authored
Add -Yimports compiler flag (#16218)
Fixes lampepfl/dotty-feature-requests#138
2 parents ef8cc3e + e0e61bd commit 86e36e7

32 files changed

+214
-9
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ private sealed trait YSettings:
281281
val Yscala2Unpickler: Setting[String] = StringSetting("-Yscala2-unpickler", "", "Control where we may get Scala 2 symbols from. This is either \"always\", \"never\", or a classpath.", "always")
282282

283283
val YnoImports: Setting[Boolean] = BooleanSetting("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.")
284+
val Yimports: Setting[List[String]] = MultiStringSetting("-Yimports", helpArg="", "Custom root imports. If set, none of scala.*, java.lang.*, or Predef.* will be imported unless explicitly included.")
284285
val YnoGenericSig: Setting[Boolean] = BooleanSetting("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.")
285286
val YnoPredef: Setting[Boolean] = BooleanSetting("-Yno-predef", "Compile without importing Predef.")
286287
val Yskip: Setting[List[String]] = PhasesSetting("-Yskip", "Skip")

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,12 +1558,21 @@ class Definitions {
15581558
private val PredefImportFns: RootRef =
15591559
RootRef(() => ScalaPredefModule.termRef, isPredef=true)
15601560

1561-
@tu private lazy val JavaRootImportFns: List[RootRef] =
1562-
if ctx.settings.YnoImports.value then Nil
1563-
else JavaImportFns
1561+
@tu private lazy val YimportsImportFns: List[RootRef] = ctx.settings.Yimports.value.map { name =>
1562+
val denot =
1563+
getModuleIfDefined(name).suchThat(_.is(Module)) `orElse`
1564+
getPackageClassIfDefined(name).suchThat(_.is(Package))
1565+
if !denot.exists then
1566+
report.error(s"error: bad preamble import $name")
1567+
val termRef = denot.symbol.termRef
1568+
RootRef(() => termRef)
1569+
}
1570+
1571+
@tu private lazy val JavaRootImportFns: List[RootRef] = JavaImportFns
15641572

15651573
@tu private lazy val ScalaRootImportFns: List[RootRef] =
1566-
if ctx.settings.YnoImports.value then Nil
1574+
if !ctx.settings.Yimports.isDefault then YimportsImportFns
1575+
else if ctx.settings.YnoImports.value then Nil
15671576
else if ctx.settings.YnoPredef.value then ScalaImportFns
15681577
else ScalaImportFns :+ PredefImportFns
15691578

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,6 @@ class CompilationTests {
151151
compileFile("tests/neg-custom-args/ovlazy.scala", scala2CompatMode.and("-Xfatal-warnings")),
152152
compileFile("tests/neg-custom-args/newline-braces.scala", scala2CompatMode.and("-Xfatal-warnings")),
153153
compileFile("tests/neg-custom-args/autoTuplingTest.scala", defaultOptions.andLanguageFeature("noAutoTupling")),
154-
compileFile("tests/neg-custom-args/nopredef.scala", defaultOptions.and("-Yno-predef")),
155-
compileFile("tests/neg-custom-args/noimports.scala", defaultOptions.and("-Yno-imports")),
156-
compileFile("tests/neg-custom-args/noimports2.scala", defaultOptions.and("-Yno-imports")),
157154
compileFile("tests/neg-custom-args/i1650.scala", allowDeepSubtypes),
158155
compileFile("tests/neg-custom-args/i3882.scala", allowDeepSubtypes),
159156
compileFile("tests/neg-custom-args/i4372.scala", allowDeepSubtypes),

tests/neg/missing-import.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class annotation extends Annotation // error
2+
val s: String = "str"
3+
val regex: Regex = s.r // error

tests/neg/noimports-additional.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// scalac: -Yno-imports -Yimports:scala.annotation,scala.util.matching
2+
class annotation extends Annotation
3+
val s: String = "str" // error
4+
val regex: Regex = new Regex("str")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// scalac: -Yno-imports
12
object Test {
23
val t: Int = 1 // error: not found Int
34
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// scalac: -Yno-imports
12
object Test {
23
assert("asdf" == "asdf") // error: not found assert
34
}

tests/neg/nopredef-additional.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// scalac: -Yno-predef -Yimports:java.lang,scala.annotation,scala.util.matching
2+
class annotation extends Annotation
3+
val s: String = "str"
4+
val regex: Regex = s.r // error

tests/neg/nopredef.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import Predef.{assert as _}
2-
1+
// scalac: -Yno-predef
32
object Test {
43
assert("asdf" == "asdf") // error: not found assert
54
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Predef.{assert as _}
2+
13
object Test {
24
assert("asdf" == "asdf") // error: not found assert
35
}

tests/neg/yimports-custom.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
-- [E006] Not Found Error: tests/neg/yimports-custom/C_2.scala:5:16 ----------------------------------------------------
3+
5 | def greet() = println("hello, world!") // error
4+
| ^^^^^^^
5+
| Not found: println
6+
|
7+
| longer explanation available when compiling with `-explain`

tests/neg/yimports-custom/C_2.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// scalac: -Yimports:hello.world.minidef
2+
3+
class C {
4+
val v: Numb = Magic
5+
def greet() = println("hello, world!") // error
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
package hello.world
3+
4+
object minidef {
5+
type Numb = Int
6+
final val Magic = 42
7+
}

tests/neg/yimports-nojava.check

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- [E006] Not Found Error: tests/neg/yimports-nojava.scala:5:16 --------------------------------------------------------
2+
5 | def g() = new Integer(42) // error
3+
| ^^^^^^^
4+
| Not found: type Integer
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E006] Not Found Error: tests/neg/yimports-nojava.scala:6:16 --------------------------------------------------------
8+
6 | def sleep() = Thread.sleep(42000L) // error
9+
| ^^^^^^
10+
| Not found: Thread
11+
|
12+
| longer explanation available when compiling with `-explain`

tests/neg/yimports-nojava.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// scalac: -Yimports:scala,scala.Predef
2+
3+
trait T {
4+
def f() = println("hello, world!")
5+
def g() = new Integer(42) // error
6+
def sleep() = Thread.sleep(42000L) // error
7+
}

tests/neg/yimports-nosuch.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error: bad preamble import skala
2+
error: bad preamble import scala.Predeff

tests/neg/yimports-nosuch.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// scalac: -Yimports:skala,scala.Predeff
2+
//
3+
class C
4+
// nopos-error
5+
// nopos-error

tests/neg/yimports-order.check

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- [E006] Not Found Error: tests/neg/yimports-order.scala:9:16 ---------------------------------------------------------
2+
9 | def f() = Map("hello" -> "world") // error // error
3+
| ^^^
4+
| Not found: Map
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E008] Not Found Error: tests/neg/yimports-order.scala:9:28 ---------------------------------------------------------
8+
9 | def f() = Map("hello" -> "world") // error // error
9+
| ^^^^^^^^^^
10+
| value -> is not a member of String
11+
-- [E006] Not Found Error: tests/neg/yimports-order.scala:10:16 --------------------------------------------------------
12+
10 | def g() = println(f()) // error
13+
| ^^^^^^^
14+
| Not found: println
15+
|
16+
| longer explanation available when compiling with `-explain`

tests/neg/yimports-order.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
package top {
3+
package middle {
4+
class C {
5+
def c() = println("hello, world")
6+
}
7+
import Predef.{Map => _}
8+
object Test {
9+
def f() = Map("hello" -> "world") // error // error
10+
def g() = println(f()) // error
11+
}
12+
}
13+
}

tests/neg/yimports-predef.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E008] Not Found Error: tests/neg/yimports-predef.scala:6:21 --------------------------------------------------------
2+
6 | def f[A](x: A) = x + 42 // error
3+
| ^^^
4+
| value + is not a member of A

tests/neg/yimports-predef.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// scalac: -Yimports:scala,scala.Predef
2+
//
3+
import Predef.{any2stringadd => _, _}
4+
5+
class classic {
6+
def f[A](x: A) = x + 42 // error
7+
}

tests/neg/yimports-stable.check

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
error: bad preamble import hello.world.potions
3+
-- [E006] Not Found Error: tests/neg/yimports-stable/C_2.scala:4:9 -----------------------------------------------------
4+
4 | val v: Numb = magic // error // error
5+
| ^^^^
6+
| Not found: type Numb
7+
|
8+
| longer explanation available when compiling with `-explain`
9+
-- [E006] Not Found Error: tests/neg/yimports-stable/C_2.scala:4:16 ----------------------------------------------------
10+
4 | val v: Numb = magic // error // error
11+
| ^^^^^
12+
| Not found: magic
13+
|
14+
| longer explanation available when compiling with `-explain`

tests/neg/yimports-stable/C_2.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// scalac: -Yimports:scala,scala.Predef,hello.world.potions
2+
//
3+
class C {
4+
val v: Numb = magic // error // error
5+
def greet() = println("hello, world!")
6+
}
7+
// nopos-error
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
package hello
3+
4+
trait stuff {
5+
type Numb = Int
6+
val magic = 42
7+
}
8+
9+
object world {
10+
val potions = new stuff {}
11+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
C_2.scala:8: error: not found: type Numb
3+
val v: Numb = Answer
4+
^
5+
-- [E006] Not Found Error: tests/neg/yimports-custom-b/C_2.scala:9:16 --------------------------------------------------
6+
9 | def greet() = println("hello, world!") // error
7+
| ^^^^^^^
8+
| Not found: println
9+
|
10+
| longer explanation available when compiling with `-explain`
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// scalac: -Yimports:hello.world.minidef
2+
3+
import hello.{world => hw}
4+
import hw.minidef.{Magic => Answer}
5+
6+
// Finds the answer, but dumb to forget Numb
7+
class C {
8+
val v: Numb = Answer // error
9+
def greet() = println("hello, world!") // error
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// scalac: -Yimports:scala
2+
3+
package hello.world
4+
5+
object minidef {
6+
type Numb = Int
7+
final val Magic = 42
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
C_2.scala:11: error: not found: type Numb
3+
val v: Numb = Answer
4+
^
5+
-- [E006] Not Found Error: tests/neg/yimports-masked/C_2.scala:12:18 ---------------------------------------------------
6+
12 | def greet() = println("hello, world!") // error
7+
| ^^^^^^^
8+
| Not found: println
9+
|
10+
| longer explanation available when compiling with `-explain`
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// scalac: -Yimports:scala,hello.world.minidef
2+
3+
// import at top level or top of package disables implicit import.
4+
// the import can appear at any statement position, here, end of package.
5+
// Update: with new trick, the import has to be completed before usages.
6+
7+
import hello.world.minidef.{Magic => Answer}
8+
9+
package p {
10+
class C {
11+
val v: Numb = Answer // error
12+
def greet() = println("hello, world!") // error
13+
}
14+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
package hello.world
3+
4+
object minidef {
5+
type Numb = Int
6+
final val Magic = 42
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// scalac: -Yimports:scala,java.lang,scala.Predef,scala.annotation,scala.util.matching
2+
3+
class annotation extends Annotation
4+
val s: String = "str"
5+
val regex: Regex = s.r
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// scalac: -Yimports:scala.annotation
2+
class annotation extends Annotation

0 commit comments

Comments
 (0)