Skip to content
Draft
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
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
.setTyper(new Typer)
.addMode(Mode.ImplicitsEnabled)
.setTyperState(ctx.typerState.fresh(ctx.reporter))
if ctx.settings.YexplicitNulls.value && !Feature.enabledBySetting(nme.unsafeNulls) then
if ctx.settings.YexplicitNulls.value || Feature.enabledBySetting(nme.safeNulls) then
start = start.addMode(Mode.SafeNulls)
ctx.initialize()(using start) // re-initialize the base context with start

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Feature.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ object Feature:
(nme.noAutoTupling, "Disable automatic tupling"),
(nme.dynamics, "Allow direct or indirect subclasses of scala.Dynamic"),
(nme.unsafeNulls, "Enable unsafe nulls for explicit nulls"),
(nme.safeNulls, "Enable safe nulls for explicit nulls"),
(nme.postfixOps, "Allow postfix operators (not recommended)"),
(nme.strictEquality, "Enable strict equality (disable canEqualAny)"),
(nme.implicitConversions, "Allow implicit conversions without warnings"),
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,8 @@ private sealed trait YSettings:
// Experimental language features
@deprecated(message = "This flag has no effect and will be removed in a future version.", since = "3.7.0")
val YnoKindPolymorphism: Setting[Boolean] = BooleanSetting(ForkSetting, "Yno-kind-polymorphism", "Disable kind polymorphism. (This flag has no effect)", deprecation = Deprecation.removed())
val YexplicitNulls: Setting[Boolean] = BooleanSetting(ForkSetting, "Yexplicit-nulls", "Make reference types non-nullable. Nullable types can be expressed with unions: e.g. String|Null.")
val YexplicitNulls: Setting[Boolean] = BooleanSetting(ForkSetting, "Yexplicit-nulls", "Since explicit nulls is enabled by default, this flag now enables safe nulls for explicit-nulls")
val YnoExplicitNulls: Setting[Boolean] = BooleanSetting(ForkSetting, "Yno-explicit-nulls", "Make reference types implictly nullable.")
val YnoFlexibleTypes: Setting[Boolean] = BooleanSetting(ForkSetting, "Yno-flexible-types", "Disable turning nullable Java return types and parameter types into flexible types, which behave like abstract types with a nullable lower bound and non-nullable upper bound.")
val YflexifyTasty: Setting[Boolean] = BooleanSetting(ForkSetting, "Yflexify-tasty", "Apply flexification to Scala code compiled without -Yexplicit-nulls, when reading from tasty.")
val YsafeInitGlobal: Setting[Boolean] = BooleanSetting(ForkSetting, "Ysafe-init-global", "Check safe initialization of global objects.")
Expand All @@ -482,6 +483,7 @@ private sealed trait YSettings:
val YexplainLowlevel: Setting[Boolean] = BooleanSetting(ForkSetting, "Yexplain-lowlevel", "When explaining type errors, show types at a lower level.")
val YnoDoubleBindings: Setting[Boolean] = BooleanSetting(ForkSetting, "Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).")
val YshowVarBounds: Setting[Boolean] = BooleanSetting(ForkSetting, "Yshow-var-bounds", "Print type variables with their bounds.")
val YhideFlexibleTypes: Setting[Boolean] = BooleanSetting(ForkSetting, "Yhide-flexible-types", "Print flexible types as their base type. (T instead of (T)?)")

val Yinstrument: Setting[Boolean] = BooleanSetting(ForkSetting, "Yinstrument", "Add instrumentation code that counts allocations and closure creations.")
val YinstrumentDefs: Setting[Boolean] = BooleanSetting(ForkSetting, "Yinstrument-defs", "Add instrumentation code that counts method calls; needs -Yinstrument to be set, too.")
Expand Down
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -484,13 +484,13 @@ object Contexts {
fresh.setSetting(ctx.settings.color, "never")

/** Is the explicit nulls option set? */
def explicitNulls: Boolean = base.settings.YexplicitNulls.value
def explicitNulls: Boolean = !base.settings.YnoExplicitNulls.value

/** Is the flexible types option set? */
def flexibleTypes: Boolean = base.settings.YexplicitNulls.value && !base.settings.YnoFlexibleTypes.value
def flexibleTypes: Boolean = explicitNulls && !base.settings.YnoFlexibleTypes.value

/** Is the flexify tasty option set? */
def flexifyTasty: Boolean = base.settings.YexplicitNulls.value && base.settings.YflexifyTasty.value
def flexifyTasty: Boolean = explicitNulls && base.settings.YflexifyTasty.value

/** Is the best-effort option set? */
def isBestEffort: Boolean = base.settings.YbestEffort.value
Expand Down Expand Up @@ -730,7 +730,9 @@ object Contexts {
importInfo.mentionsFeature(nme.unsafeNulls) match
case Some(true) =>
setMode(this.mode &~ Mode.SafeNulls)
case Some(false) if ctx.settings.YexplicitNulls.value =>
case _ =>
importInfo.mentionsFeature(nme.safeNulls) match
case Some(true) if explicitNulls =>
setMode(this.mode | Mode.SafeNulls)
case _ =>
updateStore(importInfoLoc, importInfo)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,7 @@ object StdNames {
val unbox: N = "unbox"
val universe: N = "universe"
val unsafeNulls: N = "unsafeNulls"
val safeNulls: N = "safeNulls"
val update: N = "update"
val updateDynamic: N = "updateDynamic"
val uses: N = "uses"
Expand Down
10 changes: 8 additions & 2 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,10 @@ class TreeUnpickler(reader: TastyReader,
if nothingButMods(end) then AliasingBounds(readVariances(lo))
else
val hi = readVariances(readType())
createNullableTypeBounds(lo, hi)
if (ctx.flexifyTasty && !explicitNulls)
createNullableTypeBounds(lo, hi)
else
TypeBounds(lo, hi)
case ANNOTATEDtype =>
val parent = readType()
val ann =
Expand Down Expand Up @@ -1694,7 +1697,10 @@ class TreeUnpickler(reader: TastyReader,
val lo = readTpt()
val hi = if currentAddr == end then lo else readTpt()
val alias = if currentAddr == end then EmptyTree else readTpt()
createNullableTypeBoundsTree(lo, hi, alias)
if (ctx.flexifyTasty && !explicitNulls)
createNullableTypeBoundsTree(lo, hi, alias)
else
TypeBoundsTree(lo, hi, alias)
case QUOTE =>
Quote(readTree(), Nil).withBodyType(readType())
case SPLICE =>
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,10 @@ class PlainPrinter(_ctx: Context) extends Printer {
case _ =>
toTextLocal(tpe) ~ " " ~ toText(annot)
case FlexibleType(_, tpe) =>
"(" ~ toText(tpe) ~ ")?"
if (ctx.settings.YhideFlexibleTypes.value) then
toText(tpe)
else
"(" ~ toText(tpe) ~ ")?"
case tp: TypeVar =>
def toTextCaret(tp: Type) = if printDebug then toTextLocal(tp) ~ Str("^") else toText(tp)
if (tp.isInstantiated)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Pickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ class Pickler extends Phase {
val attributes = Attributes(
sourceFile = sourceRelativePath,
scala2StandardLibrary = Feature.shouldBehaveAsScala2,
explicitNulls = ctx.settings.YexplicitNulls.value,
explicitNulls = ctx.explicitNulls,
captureChecked = Feature.ccEnabled,
withPureFuns = Feature.pureFunsEnabled,
isJava = isJavaAttr,
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -982,9 +982,9 @@ trait Applications extends Compatibility {
// However, for overload resolution, we want to check applicability:
// "could this work with some type instantiation?" (yes, if ? = String)
def wildcardArgOK =
argtpe match
argtpe.stripNull() match
case at @ AppliedType(tycon1, args1) if at.hasWildcardArg =>
formal match
formal.stripNull() match
case AppliedType(tycon2, args2)
if tycon1 =:= tycon2 && args1.length == args2.length =>
// We need to handle all 4 cases, in addition to
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ class CompilationTests {
val compilationTest = withCoverage(aggregateTests(
compileFilesInDir("tests/explicit-nulls/pos", explicitNullsOptions),
compileFilesInDir("tests/explicit-nulls/flexible-types-common", explicitNullsOptions),
compileFilesInDir("tests/explicit-nulls/unsafe-common", explicitNullsOptions `and` "-language:unsafeNulls" `and` "-Yno-flexible-types"),
compileFilesInDir("tests/explicit-nulls/unsafe-common", defaultOptions `and` "-Yno-flexible-types"),
))
runWithCoverageOrFallback[PosTestWithCoverage](compilationTest, "Pos")

Expand Down
4 changes: 2 additions & 2 deletions compiler/test/dotty/tools/vulpix/TestConfiguration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object TestConfiguration {
Properties.sourcecode
))

lazy val replWithStagingClasspath =
lazy val replWithStagingClasspath =
replClassPath + File.pathSeparator + mkClasspath(List(Properties.dottyStaging))

def mkClasspath(classpaths: List[String]): String =
Expand Down Expand Up @@ -101,7 +101,7 @@ object TestConfiguration {
val picklingWithCompilerOptions =
picklingOptions.withClasspath(withCompilerClasspath).withRunClasspath(withCompilerClasspath)

val explicitNullsOptions = defaultOptions `and` "-Yexplicit-nulls"
val explicitNullsOptions = defaultOptions `and` "-language:safeNulls"

/** Default target of the generated class files */
private def defaultTarget: String = "17"
Expand Down
12 changes: 6 additions & 6 deletions docs/_docs/reference/error-codes/E008.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,23 @@ This commonly occurs when:
## Example

```scala sc:fail sc-opts:-explain
val result = "hello".unknownMethod
val result: String = "hello".unknownMethod
```

### Error

```scala sc:nocompile
-- [E008] Not Found Error: example.scala:1:21 ----------------------------------
1 |val result = "hello".unknownMethod
| ^^^^^^^^^^^^^^^^^^^^^
| value unknownMethod is not a member of String
-- [E008] Not Found Error: example.scala:1:29 ----------------------------------
1 |val result: String = "hello".unknownMethod
| ^^^^^^^^^^^^^^^^^^^^^
| value unknownMethod is not a member of String
```

### Solution

```scala sc:compile
// Use a method that exists on the type
val result = "hello".toUpperCase
val result: String = "hello".toUpperCase
```

```scala sc:compile
Expand Down
6 changes: 3 additions & 3 deletions docs/_docs/reference/error-codes/E208.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ Extension methods are typically invoked as `receiver.method()`, where the receiv
## Example

```scala sc:fail sc-opts:-Werror
extension (s: String = "hello, world") def invert = s.reverse.toUpperCase
extension (s: String = "hello, world") def invert: String = s.reverse.toUpperCase
```

### Error

```scala sc:nocompile
-- [E208] Potential Issue Warning: example.scala:1:23 --------------------------
1 |extension (s: String = "hello, world") def invert = s.reverse.toUpperCase
1 |extension (s: String = "hello, world") def invert: String = s.reverse.toUpperCase
| ^
|Extension method invert should not have a default argument for its receiver.
|-----------------------------------------------------------------------------
Expand All @@ -44,7 +44,7 @@ it should not be defined as an extension.
Remove the default argument from the receiver parameter:

```scala sc:compile sc-opts:-Werror
extension (s: String) def invert = s.reverse.toUpperCase
extension (s: String) def invert: String = s.reverse.toUpperCase
```

If you need a function with a default argument, define it as a regular method instead of an extension:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,12 @@ class CompletionTest {

@Test def importJavaStaticMethod: Unit = {
code"""import java.lang.System.lineSep${m1}"""
.completion(("lineSeparator", Method, "(): String"))
.completion(("lineSeparator", Method, "(): (String)?"))
}

@Test def importJavaStaticField: Unit = {
code"""import java.lang.System.ou${m1}"""
.completion(("out", Field, "java.io.PrintStream"))
.completion(("out", Field, "(java.io.PrintStream)?"))
}

@Test def importFromExplicitAndSyntheticPackageObject: Unit = {
Expand Down
3 changes: 3 additions & 0 deletions library/src/scala/language.scala
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ object language {
@compileTimeOnly("`unsafeNulls` can only be used at compile time in import statements")
object unsafeNulls

@compileTimeOnly("`safeNulls` can only be used at compile time in import statements")
object safeNulls

@compileTimeOnly("`future` can only be used at compile time in import statements")
object future

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ final class InferredMethodProvider(
Interactive.pathTo(driver.openedTrees(uri), pos)(using driver.currentCtx)

given locatedCtx: Context = driver.localContext(params)
val indexedCtx = IndexedContext(pos)(using locatedCtx)
val locatedCtx2 = locatedCtx.fresh.setSettings(ctx.settings.YhideFlexibleTypes.updateIn(
ctx.settingsState.reinitializedCopy(),
true
))
val indexedCtx = IndexedContext(pos)(using locatedCtx2)

val autoImportsGen = AutoImports.generator(
pos,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ final class InferredTypeProvider(
Interactive.pathTo(driver.openedTrees(uri), pos)(using driver.currentCtx)

given locatedCtx: Context = driver.localContext(params)
val indexedCtx = IndexedContext(pos)(using locatedCtx)
val locatedCtx2 = locatedCtx.fresh.setSettings(ctx.settings.YhideFlexibleTypes.updateIn(
ctx.settingsState.reinitializedCopy(),
true
))
val indexedCtx = IndexedContext(pos)(using locatedCtx2)
val autoImportsGen = AutoImports.generator(
pos,
sourceText,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class CompletionProvider(
case Some(unit) =>
val newctx = ctx.fresh
.setCompilationUnit(unit)
.setSettings(ctx.settings.YhideFlexibleTypes.updateIn(ctx.settingsState.reinitializedCopy(), true))
.setProfiler(Profiler()(using ctx))
.withPhase(Phases.typerPhase(using ctx))
val tpdPath0 = Interactive.pathTo(unit.tpdTree, pos.span)(using newctx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ class HoverDocSuite extends BaseHoverSuite:
|""".stripMargin,
"""|**Expression type**:
|```scala
|java.util.List[Int]
|(java.util.List[Int])?
|```
|**Symbol signature**:
|```scala
|final def emptyList[T](): java.util.List[T]
|final def emptyList[T](): (java.util.List[T])?
|```
|Found documentation for java/util/Collections#emptyList().
|""".stripMargin
Expand All @@ -57,7 +57,7 @@ class HoverDocSuite extends BaseHoverSuite:
|}
""".stripMargin,
"""|```scala
|def substring(beginIndex: Int): String
|def substring(beginIndex: Int): (String)?
|```
|Found documentation for java/lang/String#substring().
|""".stripMargin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -818,15 +818,15 @@ class HoverTermSuite extends BaseHoverSuite:
"""|package tests.macros
|def m = Macros7460.foo.sub@@string(2, 4)
|""".stripMargin,
"def substring(x$0: Int, x$1: Int): String".hover
"def substring(x$0: Int, x$1: Int): (String)?".hover
)

@Test def `i7460-2` =
check(
"""|package tests.macros
|def m = Macros7460.bar.sub@@string(2, 4)
|""".stripMargin,
"def substring(x$0: Int, x$1: Int): String".hover
"def substring(x$0: Int, x$1: Int): (String)?".hover
)

@Test def `multiple-valdefs-1` =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1270,8 +1270,8 @@ class InlayHintsSuite extends BaseInlayHintsSuite {
|""".stripMargin,
"""|object Main {
| val str/*: String<<java/lang/String#>>*/ = "hello"
| val sub/*: String<<java/lang/String#>>*/ = str.substring(1, 3)
| val replaced/*: String<<java/lang/String#>>*/ = str.replace('l', 'x')
| val sub/*: (String<<java/lang/String#>>)?*/ = str.substring(1, 3)
| val replaced/*: (String<<java/lang/String#>>)?*/ = str.replace('l', 'x')
|}
|""".stripMargin
)
Expand Down
Loading
Loading