Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -Yimports compiler flag #16218

Merged
merged 4 commits into from
Nov 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ private sealed trait YSettings:
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")

val YnoImports: Setting[Boolean] = BooleanSetting("-Yno-imports", "Compile without importing scala.*, java.lang.*, or Predef.")
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.")
val YnoGenericSig: Setting[Boolean] = BooleanSetting("-Yno-generic-signatures", "Suppress generation of generic signatures for Java.")
val YnoPredef: Setting[Boolean] = BooleanSetting("-Yno-predef", "Compile without importing Predef.")
val Yskip: Setting[List[String]] = PhasesSetting("-Yskip", "Skip")
Expand Down
17 changes: 13 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1558,12 +1558,21 @@ class Definitions {
private val PredefImportFns: RootRef =
RootRef(() => ScalaPredefModule.termRef, isPredef=true)

@tu private lazy val JavaRootImportFns: List[RootRef] =
if ctx.settings.YnoImports.value then Nil
else JavaImportFns
@tu private lazy val YimportsImportFns: List[RootRef] = ctx.settings.Yimports.value.map { name =>
val denot =
getModuleIfDefined(name).suchThat(_.is(Module)) `orElse`
getPackageClassIfDefined(name).suchThat(_.is(Package))
if !denot.exists then
report.error(s"error: bad preamble import $name")
val termRef = denot.symbol.termRef
RootRef(() => termRef)
}

@tu private lazy val JavaRootImportFns: List[RootRef] = JavaImportFns

@tu private lazy val ScalaRootImportFns: List[RootRef] =
if ctx.settings.YnoImports.value then Nil
if !ctx.settings.Yimports.isDefault then YimportsImportFns
else if ctx.settings.YnoImports.value then Nil
else if ctx.settings.YnoPredef.value then ScalaImportFns
else ScalaImportFns :+ PredefImportFns

Expand Down
3 changes: 0 additions & 3 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,6 @@ class CompilationTests {
compileFile("tests/neg-custom-args/ovlazy.scala", scala2CompatMode.and("-Xfatal-warnings")),
compileFile("tests/neg-custom-args/newline-braces.scala", scala2CompatMode.and("-Xfatal-warnings")),
compileFile("tests/neg-custom-args/autoTuplingTest.scala", defaultOptions.andLanguageFeature("noAutoTupling")),
compileFile("tests/neg-custom-args/nopredef.scala", defaultOptions.and("-Yno-predef")),
compileFile("tests/neg-custom-args/noimports.scala", defaultOptions.and("-Yno-imports")),
compileFile("tests/neg-custom-args/noimports2.scala", defaultOptions.and("-Yno-imports")),
compileFile("tests/neg-custom-args/i1650.scala", allowDeepSubtypes),
compileFile("tests/neg-custom-args/i3882.scala", allowDeepSubtypes),
compileFile("tests/neg-custom-args/i4372.scala", allowDeepSubtypes),
Expand Down
3 changes: 3 additions & 0 deletions tests/neg/missing-import.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class annotation extends Annotation // error
val s: String = "str"
val regex: Regex = s.r // error
4 changes: 4 additions & 0 deletions tests/neg/noimports-additional.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// scalac: -Yno-imports -Yimports:scala.annotation,scala.util.matching
class annotation extends Annotation
val s: String = "str" // error
val regex: Regex = new Regex("str")
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// scalac: -Yno-imports
object Test {
val t: Int = 1 // error: not found Int
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// scalac: -Yno-imports
object Test {
assert("asdf" == "asdf") // error: not found assert
}
4 changes: 4 additions & 0 deletions tests/neg/nopredef-additional.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// scalac: -Yno-predef -Yimports:java.lang,scala.annotation,scala.util.matching
class annotation extends Annotation
val s: String = "str"
val regex: Regex = s.r // error
3 changes: 1 addition & 2 deletions tests/neg/nopredef.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Predef.{assert as _}

// scalac: -Yno-predef
object Test {
assert("asdf" == "asdf") // error: not found assert
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Predef.{assert as _}

object Test {
assert("asdf" == "asdf") // error: not found assert
}
7 changes: 7 additions & 0 deletions tests/neg/yimports-custom.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

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

class C {
val v: Numb = Magic
def greet() = println("hello, world!") // error
}
7 changes: 7 additions & 0 deletions tests/neg/yimports-custom/minidef_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

package hello.world

object minidef {
type Numb = Int
final val Magic = 42
}
12 changes: 12 additions & 0 deletions tests/neg/yimports-nojava.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- [E006] Not Found Error: tests/neg/yimports-nojava.scala:5:16 --------------------------------------------------------
5 | def g() = new Integer(42) // error
| ^^^^^^^
| Not found: type Integer
|
| longer explanation available when compiling with `-explain`
-- [E006] Not Found Error: tests/neg/yimports-nojava.scala:6:16 --------------------------------------------------------
6 | def sleep() = Thread.sleep(42000L) // error
| ^^^^^^
| Not found: Thread
|
| longer explanation available when compiling with `-explain`
7 changes: 7 additions & 0 deletions tests/neg/yimports-nojava.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// scalac: -Yimports:scala,scala.Predef

trait T {
def f() = println("hello, world!")
def g() = new Integer(42) // error
def sleep() = Thread.sleep(42000L) // error
}
2 changes: 2 additions & 0 deletions tests/neg/yimports-nosuch.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: bad preamble import skala
error: bad preamble import scala.Predeff
5 changes: 5 additions & 0 deletions tests/neg/yimports-nosuch.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// scalac: -Yimports:skala,scala.Predeff
//
class C
// nopos-error
// nopos-error
16 changes: 16 additions & 0 deletions tests/neg/yimports-order.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- [E006] Not Found Error: tests/neg/yimports-order.scala:9:16 ---------------------------------------------------------
9 | def f() = Map("hello" -> "world") // error // error
| ^^^
| Not found: Map
|
| longer explanation available when compiling with `-explain`
-- [E008] Not Found Error: tests/neg/yimports-order.scala:9:28 ---------------------------------------------------------
9 | def f() = Map("hello" -> "world") // error // error
| ^^^^^^^^^^
| value -> is not a member of String
-- [E006] Not Found Error: tests/neg/yimports-order.scala:10:16 --------------------------------------------------------
10 | def g() = println(f()) // error
| ^^^^^^^
| Not found: println
|
| longer explanation available when compiling with `-explain`
13 changes: 13 additions & 0 deletions tests/neg/yimports-order.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

package top {
package middle {
class C {
def c() = println("hello, world")
}
import Predef.{Map => _}
object Test {
def f() = Map("hello" -> "world") // error // error
def g() = println(f()) // error
}
}
}
4 changes: 4 additions & 0 deletions tests/neg/yimports-predef.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- [E008] Not Found Error: tests/neg/yimports-predef.scala:6:21 --------------------------------------------------------
6 | def f[A](x: A) = x + 42 // error
| ^^^
| value + is not a member of A
7 changes: 7 additions & 0 deletions tests/neg/yimports-predef.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// scalac: -Yimports:scala,scala.Predef
//
import Predef.{any2stringadd => _, _}

class classic {
def f[A](x: A) = x + 42 // error
}
14 changes: 14 additions & 0 deletions tests/neg/yimports-stable.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

error: bad preamble import hello.world.potions
-- [E006] Not Found Error: tests/neg/yimports-stable/C_2.scala:4:9 -----------------------------------------------------
4 | val v: Numb = magic // error // error
| ^^^^
| Not found: type Numb
|
| longer explanation available when compiling with `-explain`
-- [E006] Not Found Error: tests/neg/yimports-stable/C_2.scala:4:16 ----------------------------------------------------
4 | val v: Numb = magic // error // error
| ^^^^^
| Not found: magic
|
| longer explanation available when compiling with `-explain`
7 changes: 7 additions & 0 deletions tests/neg/yimports-stable/C_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// scalac: -Yimports:scala,scala.Predef,hello.world.potions
//
class C {
val v: Numb = magic // error // error
def greet() = println("hello, world!")
}
// nopos-error
11 changes: 11 additions & 0 deletions tests/neg/yimports-stable/minidef_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

package hello

trait stuff {
type Numb = Int
val magic = 42
}

object world {
val potions = new stuff {}
}
10 changes: 10 additions & 0 deletions tests/pending/neg/yimports-custom-b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

C_2.scala:8: error: not found: type Numb
val v: Numb = Answer
^
-- [E006] Not Found Error: tests/neg/yimports-custom-b/C_2.scala:9:16 --------------------------------------------------
9 | def greet() = println("hello, world!") // error
| ^^^^^^^
| Not found: println
|
| longer explanation available when compiling with `-explain`
10 changes: 10 additions & 0 deletions tests/pending/neg/yimports-custom-b/C_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// scalac: -Yimports:hello.world.minidef

import hello.{world => hw}
import hw.minidef.{Magic => Answer}

// Finds the answer, but dumb to forget Numb
class C {
val v: Numb = Answer // error
def greet() = println("hello, world!") // error
}
8 changes: 8 additions & 0 deletions tests/pending/neg/yimports-custom-b/minidef_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// scalac: -Yimports:scala

package hello.world

object minidef {
type Numb = Int
final val Magic = 42
}
10 changes: 10 additions & 0 deletions tests/pending/neg/yimports-masked.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

C_2.scala:11: error: not found: type Numb
val v: Numb = Answer
^
-- [E006] Not Found Error: tests/neg/yimports-masked/C_2.scala:12:18 ---------------------------------------------------
12 | def greet() = println("hello, world!") // error
| ^^^^^^^
| Not found: println
|
| longer explanation available when compiling with `-explain`
14 changes: 14 additions & 0 deletions tests/pending/neg/yimports-masked/C_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// scalac: -Yimports:scala,hello.world.minidef

// import at top level or top of package disables implicit import.
// the import can appear at any statement position, here, end of package.
// Update: with new trick, the import has to be completed before usages.

import hello.world.minidef.{Magic => Answer}

package p {
class C {
val v: Numb = Answer // error
def greet() = println("hello, world!") // error
}
}
7 changes: 7 additions & 0 deletions tests/pending/neg/yimports-masked/minidef_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

package hello.world

object minidef {
type Numb = Int
final val Magic = 42
}
5 changes: 5 additions & 0 deletions tests/pos/multiple-additional-imports.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// scalac: -Yimports:scala,java.lang,scala.Predef,scala.annotation,scala.util.matching

class annotation extends Annotation
val s: String = "str"
val regex: Regex = s.r
2 changes: 2 additions & 0 deletions tests/pos/single-additional-import.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// scalac: -Yimports:scala.annotation
class annotation extends Annotation