Skip to content

Commit 36159bb

Browse files
authored
Merge pull request #11231 from dotty-staging/fix-11225
Use `unitialized` for wildcard initializers
2 parents 49389b3 + 90907ed commit 36159bb

File tree

68 files changed

+282
-118
lines changed

Some content is hidden

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

68 files changed

+282
-118
lines changed

bench/tests/Vector.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import scala.annotation.unchecked.uncheckedVariance
1414
import scala.compat.Platform
1515
import scala.collection.generic._
1616
import scala.collection.mutable.Builder
17+
import compiletime.uninitialized
1718

1819
/** Companion object to the Vector class
1920
*/
@@ -741,13 +742,13 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A
741742

742743

743744
private[immutable] trait VectorPointer[T] {
744-
private[immutable] var depth: Int = _
745-
private[immutable] var display0: Array[AnyRef] = _
746-
private[immutable] var display1: Array[AnyRef] = _
747-
private[immutable] var display2: Array[AnyRef] = _
748-
private[immutable] var display3: Array[AnyRef] = _
749-
private[immutable] var display4: Array[AnyRef] = _
750-
private[immutable] var display5: Array[AnyRef] = _
745+
private[immutable] var depth: Int = uninitialized
746+
private[immutable] var display0: Array[AnyRef] = uninitialized
747+
private[immutable] var display1: Array[AnyRef] = uninitialized
748+
private[immutable] var display2: Array[AnyRef] = uninitialized
749+
private[immutable] var display3: Array[AnyRef] = uninitialized
750+
private[immutable] var display4: Array[AnyRef] = uninitialized
751+
private[immutable] var display5: Array[AnyRef] = uninitialized
751752

752753
// used
753754
private[immutable] final def initFrom[U](that: VectorPointer[U]): Unit = initFrom(that, that.depth)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,9 @@ class Definitions {
226226
@tu lazy val CompiletimePackageObject: Symbol = requiredModule("scala.compiletime.package")
227227
@tu lazy val Compiletime_codeOf: Symbol = CompiletimePackageObject.requiredMethod("codeOf")
228228
@tu lazy val Compiletime_erasedValue : Symbol = CompiletimePackageObject.requiredMethod("erasedValue")
229+
@tu lazy val Compiletime_uninitialized: Symbol = CompiletimePackageObject.requiredMethod("uninitialized")
229230
@tu lazy val Compiletime_error : Symbol = CompiletimePackageObject.requiredMethod(nme.error)
230-
@tu lazy val Compiletime_requireConst: Symbol = CompiletimePackageObject.requiredMethod("requireConst")
231+
@tu lazy val Compiletime_requireConst : Symbol = CompiletimePackageObject.requiredMethod("requireConst")
231232
@tu lazy val Compiletime_constValue : Symbol = CompiletimePackageObject.requiredMethod("constValue")
232233
@tu lazy val Compiletime_constValueOpt: Symbol = CompiletimePackageObject.requiredMethod("constValueOpt")
233234
@tu lazy val Compiletime_summonFrom : Symbol = CompiletimePackageObject.requiredMethod("summonFrom")

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3201,7 +3201,8 @@ object Parsers {
32013201

32023202
/** PatDef ::= ids [‘:’ Type] ‘=’ Expr
32033203
* | Pattern2 [‘:’ Type] ‘=’ Expr
3204-
* VarDef ::= PatDef | id {`,' id} `:' Type `=' `_'
3204+
* VarDef ::= PatDef
3205+
* | id {`,' id} `:' Type `=' `_' (deprecated in 3.1)
32053206
* ValDcl ::= id {`,' id} `:' Type
32063207
* VarDcl ::= id {`,' id} `:' Type
32073208
*/
@@ -3224,9 +3225,14 @@ object Parsers {
32243225
val rhs =
32253226
if tpt.isEmpty || in.token == EQUALS then
32263227
accept(EQUALS)
3228+
val rhsOffset = in.offset
32273229
subExpr() match
32283230
case rhs0 @ Ident(name) if placeholderParams.nonEmpty && name == placeholderParams.head.name
32293231
&& !tpt.isEmpty && mods.is(Mutable) && lhs.forall(_.isInstanceOf[Ident]) =>
3232+
if sourceVersion.isAtLeast(`3.1`) then
3233+
deprecationWarning(
3234+
em"""`= _` has been deprecated; use `= uninitialized` instead.
3235+
|`uninitialized` can be imported with `scala.compiletime.uninitialized`.""", rhsOffset)
32303236
placeholderParams = placeholderParams.tail
32313237
atSpan(rhs0.span) { Ident(nme.WILDCARD) }
32323238
case rhs0 => rhs0

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Symbols._
1010
import Types._
1111
import typer.RefChecks
1212
import MegaPhase.MiniPhase
13+
import StdNames.nme
1314
import ast.tpd
1415

1516
/** This phase makes all erased term members of classes private so that they cannot
@@ -18,6 +19,10 @@ import ast.tpd
1819
* The phase also replaces all expressions that appear in an erased context by
1920
* default values. This is necessary so that subsequent checking phases such
2021
* as IsInstanceOfChecker don't give false negatives.
22+
* Finally, the phase replaces `compiletime.uninitialized` on the right hand side
23+
* of a mutable field definition by `_`. This avoids a "is declared erased, but is
24+
* in fact used" error in Erasure and communicates to Constructors that the
25+
* variable does not have an initializer.
2126
*/
2227
class PruneErasedDefs extends MiniPhase with SymTransformer { thisTransform =>
2328
import tpd._
@@ -38,10 +43,25 @@ class PruneErasedDefs extends MiniPhase with SymTransformer { thisTransform =>
3843
cpy.Apply(tree)(tree.fun, tree.args.map(trivialErasedTree))
3944
else tree
4045

46+
private def hasUninitializedRHS(tree: ValOrDefDef)(using Context): Boolean =
47+
def recur(rhs: Tree): Boolean = rhs match
48+
case rhs: RefTree =>
49+
rhs.symbol == defn.Compiletime_uninitialized
50+
&& tree.symbol.is(Mutable) && tree.symbol.owner.isClass
51+
case closureDef(ddef) if defn.isContextFunctionType(tree.tpt.tpe.dealias) =>
52+
recur(ddef.rhs)
53+
case _ =>
54+
false
55+
recur(tree.rhs)
56+
4157
override def transformValDef(tree: ValDef)(using Context): Tree =
42-
if (tree.symbol.isEffectivelyErased && !tree.rhs.isEmpty)
58+
val sym = tree.symbol
59+
if tree.symbol.isEffectivelyErased && !tree.rhs.isEmpty then
4360
cpy.ValDef(tree)(rhs = trivialErasedTree(tree))
44-
else tree
61+
else if hasUninitializedRHS(tree) then
62+
cpy.ValDef(tree)(rhs = cpy.Ident(tree.rhs)(nme.WILDCARD).withType(tree.tpt.tpe))
63+
else
64+
tree
4565

4666
override def transformDefDef(tree: DefDef)(using Context): Tree =
4767
if (tree.symbol.isEffectivelyErased && !tree.rhs.isEmpty)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class CompilationTests {
119119
aggregateTests(
120120
compileFilesInDir("tests/neg", defaultOptions),
121121
compileFilesInDir("tests/neg-tailcall", defaultOptions),
122-
compileFilesInDir("tests/neg-strict", defaultOptions.and("-source", "3.1", "-Xfatal-warnings")),
122+
compileFilesInDir("tests/neg-strict", defaultOptions.and("-source", "3.1", "-deprecation", "-Xfatal-warnings")),
123123
compileFilesInDir("tests/neg-no-kind-polymorphism", defaultOptions and "-Yno-kind-polymorphism"),
124124
compileFilesInDir("tests/neg-custom-args/deprecation", defaultOptions.and("-Xfatal-warnings", "-deprecation")),
125125
compileFilesInDir("tests/neg-custom-args/fatal-warnings", defaultOptions.and("-Xfatal-warnings")),

docs/docs/internals/syntax.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,14 +384,12 @@ TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds
384384
[‘=’ Type]
385385
386386
Def ::= ‘val’ PatDef
387-
| ‘var’ VarDef
387+
| ‘var’ PatDef
388388
| ‘def’ DefDef
389389
| ‘type’ {nl} TypeDcl
390390
| TmplDef
391391
PatDef ::= ids [‘:’ Type] ‘=’ Expr
392-
| Pattern2 [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr)
393-
VarDef ::= PatDef
394-
| ids ‘:’ Type ‘=’ ‘_’
392+
| Pattern2 [‘:’ Type] ‘=’ Expr PatDef(_, pats, tpe?, expr)
395393
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr DefDef(_, name, tparams, vparamss, tpe, expr)
396394
| ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr DefDef(_, <init>, Nil, vparamss, EmptyTree, expr | Block)
397395
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
layout: doc-page
3+
title: "Dropped: wildcard initializer"
4+
---
5+
6+
The syntax
7+
```scala
8+
var x: A = _
9+
```
10+
that was used to indicate an uninitialized field, has been dropped.
11+
At its place there is a special value `uninitialized` in the `scala.compiletime` package. To get an uninitialized field, you now write
12+
```scala
13+
import scala.compiletime.uninitialized
14+
15+
var x: A = uninitialized
16+
```
17+
To enable cross-compilation, `_` is still supported, but it will be dropped in a future 3.x version.
18+

docs/docs/reference/syntax.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,14 +374,12 @@ DefSig ::= id [DefTypeParamClause] DefParamClauses
374374
TypeDcl ::= id [TypeParamClause] {FunParamClause} TypeBounds [‘=’ Type]
375375
376376
Def ::= ‘val’ PatDef
377-
| ‘var’ VarDef
377+
| ‘var’ PatDef
378378
| ‘def’ DefDef
379379
| ‘type’ {nl} TypeDcl
380380
| TmplDef
381381
PatDef ::= ids [‘:’ Type] ‘=’ Expr
382382
| Pattern2 [‘:’ Type] ‘=’ Expr
383-
VarDef ::= PatDef
384-
| ids ‘:’ Type ‘=’ ‘_’
385383
DefDef ::= DefSig [‘:’ Type] ‘=’ Expr
386384
| ‘this’ DefParamClause DefParamClauses ‘=’ ConstrExpr
387385

docs/sidebar.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ sidebar:
189189
url: docs/reference/dropped-features/nonlocal-returns.html
190190
- title: "[this] Qualifier"
191191
url: docs/reference/dropped-features/this-qualifier.html
192+
- title: Wildcard initializers
193+
url: docs/reference/dropped-features/wildcard-init.html
192194
- title: Syntax Summary
193195
url: docs/reference/syntax.html
194196
- title: Contributing

library/src/scala/compiletime/package.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package scala
2-
3-
import scala.quoted._
2+
import annotation.compileTimeOnly
43

54
package object compiletime {
65

@@ -18,6 +17,17 @@ package object compiletime {
1817
*/
1918
erased def erasedValue[T]: T = ???
2019

20+
/** Used as the initializer of a mutable class or object field, like this:
21+
*
22+
* var x: T = uninitialized
23+
*
24+
* This signifies that the field is not initialized on its own. It is still initialized
25+
* as part of the bulk initialization of the object it belongs to, which assigns zero
26+
* values such as `null`, `0`, `0.0`, `false` to all object fields.
27+
*/
28+
@compileTimeOnly("`uninitialized` can only be used as the right hand side of a mutable field definition")
29+
def uninitialized: Nothing = ???
30+
2131
/** The error method is used to produce user-defined compile errors during inline expansion.
2232
* If an inline expansion results in a call error(msgStr) the compiler produces an error message containing the given msgStr.
2333
*

0 commit comments

Comments
 (0)