Skip to content

Commit a393925

Browse files
authored
Merge branch 'main' into en-migrate-main
2 parents 48eba1c + 72acaef commit a393925

20 files changed

+164
-56
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
351351
}
352352
else parents
353353
val cls = newNormalizedClassSymbol(owner, tpnme.ANON_CLASS, Synthetic | Final, parents1,
354-
newScope, coord = fns.map(_.span).reduceLeft(_ union _))
354+
coord = fns.map(_.span).reduceLeft(_ union _))
355355
val constr = newConstructor(cls, Synthetic, Nil, Nil).entered
356356
def forwarder(fn: TermSymbol, name: TermName) = {
357357
val fwdMeth = fn.copy(cls, name, Synthetic | Method | Final).entered.asTerm

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,9 @@ object Contexts {
714714

715715
def withNotNullInfos(infos: List[NotNullInfo]): Context =
716716
if c.notNullInfos eq infos then c else c.fresh.setNotNullInfos(infos)
717+
718+
def relaxedOverrideContext: Context =
719+
c.withModeBits(c.mode &~ Mode.SafeNulls | Mode.RelaxedOverriding)
717720
end ops
718721

719722
// TODO: Fix issue when converting ModeChanges and FreshModeChanges to extension givens

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,6 @@ object Symbols {
567567
name: TypeName,
568568
flags: FlagSet,
569569
parentTypes: List[Type],
570-
decls: Scope,
571570
selfInfo: Type = NoType,
572571
privateWithin: Symbol = NoSymbol,
573572
coord: Coord = NoCoord,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
786786
case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2)
787787
case OrType(tp1, tp2) => isNullable(tp1) || isNullable(tp2)
788788
case _ => false
789-
789+
790790
val sym1 = tp1.symbol
791791
(sym1 eq NothingClass) && tp2.isValueTypeOrLambda ||
792792
(sym1 eq NullClass) && isNullable(tp2)

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,9 +1115,7 @@ object Types {
11151115
*/
11161116
def matches(that: Type)(using Context): Boolean = {
11171117
record("matches")
1118-
val overrideCtx = if ctx.explicitNulls
1119-
then ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding)
1120-
else ctx
1118+
val overrideCtx = if ctx.explicitNulls then ctx.relaxedOverrideContext else ctx
11211119
TypeComparer.matchesType(this, that, relaxed = !ctx.phase.erasedTypes)(using overrideCtx)
11221120
}
11231121

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ object Scanners {
265265
val next = newTokenData
266266
private val prev = newTokenData
267267

268-
/** The current region. This is initially an Indented region with indentation width. */
268+
/** The current region. This is initially an Indented region with zero indentation width. */
269269
var currentRegion: Region = Indented(IndentWidth.Zero, Set(), EMPTY, null)
270270

271271
// Get next token ------------------------------------------------------------
@@ -434,8 +434,8 @@ object Scanners {
434434
&& !migrateTo3
435435
&& !noindentSyntax
436436

437-
/** The indentation width of the given offset */
438-
def indentWidth(offset: Offset): IndentWidth = {
437+
/** The indentation width of the given offset. */
438+
def indentWidth(offset: Offset): IndentWidth =
439439
import IndentWidth.{Run, Conc}
440440
def recur(idx: Int, ch: Char, n: Int, k: IndentWidth => IndentWidth): IndentWidth =
441441
if (idx < 0) k(Run(ch, n))
@@ -452,7 +452,7 @@ object Scanners {
452452
else recur(idx - 1, ' ', 0, identity)
453453
}
454454
recur(offset - 1, ' ', 0, identity)
455-
}
455+
end indentWidth
456456

457457
/** Handle newlines, possibly inserting an INDENT, OUTDENT, NEWLINE, or NEWLINES token
458458
* in front of the current token. This depends on whether indentation is significant or not.
@@ -521,6 +521,7 @@ object Scanners {
521521
lastWidth = r.width
522522
newlineIsSeparating = lastWidth <= nextWidth || r.isOutermost
523523
indentPrefix = r.prefix
524+
case _: InString => ()
524525
case r =>
525526
indentIsSignificant = indentSyntax
526527
r.proposeKnownWidth(nextWidth, lastToken)
@@ -1422,7 +1423,7 @@ object Scanners {
14221423
nextToken()
14231424
currentRegion = topLevelRegion(indentWidth(offset))
14241425
}
1425-
// end Scanner
1426+
end Scanner
14261427

14271428
/** A Region indicates what encloses the current token. It can be one of the following
14281429
*

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class ExpandSAMs extends MiniPhase:
129129
val parents = List(
130130
defn.AbstractPartialFunctionClass.typeRef.appliedTo(anonTpe.firstParamTypes.head, anonTpe.resultType),
131131
defn.SerializableType)
132-
val pfSym = newNormalizedClassSymbol(anonSym.owner, tpnme.ANON_CLASS, Synthetic | Final, parents, newScope, coord = tree.span)
132+
val pfSym = newNormalizedClassSymbol(anonSym.owner, tpnme.ANON_CLASS, Synthetic | Final, parents, coord = tree.span)
133133

134134
def overrideSym(sym: Symbol) = sym.copy(
135135
owner = pfSym,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ object OverridingPairs:
221221
// releaxed override check for explicit nulls if one of the symbols is Java defined,
222222
// force `Null` to be a subtype of non-primitive value types during override checking.
223223
val overrideCtx = if ctx.explicitNulls && (member.is(JavaDefined) || other.is(JavaDefined))
224-
then ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding) else ctx
224+
then ctx.relaxedOverrideContext else ctx
225225
member.name.is(DefaultGetterName) // default getters are not checked for compatibility
226226
|| memberTp.overrides(otherTp,
227227
member.matchNullaryLoosely || other.matchNullaryLoosely || fallBack

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ object ResolveSuper {
114114
val otherTp = other.asSeenFrom(base.typeRef).info
115115
val accTp = acc.asSeenFrom(base.typeRef).info
116116
// Since the super class can be Java defined,
117-
// we use releaxed overriding check for explicit nulls if one of the symbols is Java defined.
117+
// we use relaxed overriding check for explicit nulls if one of the symbols is Java defined.
118118
// This forces `Null` to be a subtype of non-primitive value types during override checking.
119119
val overrideCtx = if ctx.explicitNulls && (sym.is(JavaDefined) || acc.is(JavaDefined))
120-
then ctx.retractMode(Mode.SafeNulls).addMode(Mode.RelaxedOverriding) else ctx
120+
then ctx.relaxedOverrideContext else ctx
121121
if !otherTp.overrides(accTp, matchLoosely = true)(using overrideCtx) then
122122
report.error(IllegalSuperAccessor(base, memberName, targetName, acc, accTp, other.symbol, otherTp), base.srcPos)
123123
bcs = bcs.tail

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -332,12 +332,6 @@ class SpaceEngine(using Context) extends SpaceLogic {
332332

333333
private val constantNullType = ConstantType(Constant(null))
334334

335-
/** Does the given tree stand for the literal `null`? */
336-
def isNullLit(tree: Tree): Boolean = tree match {
337-
case Literal(Constant(null)) => true
338-
case _ => false
339-
}
340-
341335
override def intersectUnrelatedAtomicTypes(tp1: Type, tp2: Type): Space = trace(s"atomic intersection: ${AndType(tp1, tp2).show}", debug) {
342336
// Precondition: !isSubType(tp1, tp2) && !isSubType(tp2, tp1).
343337
if !ctx.mode.is(Mode.SafeNulls) && (tp1.isNullType || tp2.isNullType) then

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1802,7 +1802,7 @@ final class SearchRoot extends SearchHistory:
18021802
// }
18031803

18041804
val parents = List(defn.ObjectType, defn.SerializableType)
1805-
val classSym = newNormalizedClassSymbol(ctx.owner, LazyImplicitName.fresh().toTypeName, Synthetic | Final, parents, newScope, coord = span)
1805+
val classSym = newNormalizedClassSymbol(ctx.owner, LazyImplicitName.fresh().toTypeName, Synthetic | Final, parents, coord = span)
18061806
val vsyms = pruned.map(_._1.symbol)
18071807
val nsyms = vsyms.map(vsym => newSymbol(classSym, vsym.name, EmptyFlags, vsym.info, coord = span).entered)
18081808
val vsymMap = (vsyms zip nsyms).toMap

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ object Inliner {
201201

202202
val UnApply(fun, implicits, patterns) = unapp
203203
val sym = unapp.symbol
204-
val cls = newNormalizedClassSymbol(ctx.owner, tpnme.ANON_CLASS, Synthetic | Final, List(defn.ObjectType), newScope, coord = sym.coord)
204+
val cls = newNormalizedClassSymbol(ctx.owner, tpnme.ANON_CLASS, Synthetic | Final, List(defn.ObjectType), coord = sym.coord)
205205
val constr = newConstructor(cls, Synthetic, Nil, Nil, coord = sym.coord).entered
206206

207207
val targs = fun match

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ class CompilationTests {
247247
aggregateTests(
248248
compileFilesInDir("tests/explicit-nulls/pos", explicitNullsOptions),
249249
compileFilesInDir("tests/explicit-nulls/pos-separate", explicitNullsOptions),
250+
compileFilesInDir("tests/explicit-nulls/pos-patmat", explicitNullsOptions and "-Xfatal-warnings"),
250251
compileFilesInDir("tests/explicit-nulls/unsafe-common", explicitNullsOptions and "-language:unsafeNulls"),
251252
)
252253
}.checkCompile()

tests/explicit-nulls/neg-patmat/patmat1.scala renamed to tests/explicit-nulls/neg-patmat/match-pat.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
class Foo {
2+
23
val s: String = ???
3-
s match {
4-
case s: String => 100 // warning: type test will always succeed
5-
case _ => 200 // error: unreachable
6-
}
74

85
s match {
9-
case s: String => 100 // warning: type test will always succeed
6+
case s: String => 100
107
case _ => 200 // error: unreachable
118
}
129

@@ -15,20 +12,23 @@ class Foo {
1512
case object Cat extends Animal
1613

1714
val a: Animal = ???
15+
1816
a match {
1917
case Dog(name) => 100
2018
case Cat => 200
2119
case _ => 300 // error: unreachable
2220
}
2321

24-
val a2: Animal|Null = ???
22+
val a2: Animal | Null = ???
23+
2524
a2 match {
2625
case Dog(_) => 100
2726
case Cat => 200
2827
case _ => 300
2928
}
3029

31-
val a3: Animal|Null = ???
30+
val a3: Animal | Null = ???
31+
3232
a3 match {
3333
case Dog(_) => 100
3434
case Cat => 200
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Unboxed option type using unions + null + opaque.
2+
// Relies on the fact that Null is not a subtype of AnyRef.
3+
// Test suggested by Sébastien Doeraene.
4+
5+
object Nullables {
6+
opaque type Nullable[+A <: AnyRef] = A | Null // disjoint by construction!
7+
8+
object Nullable:
9+
def apply[A <: AnyRef](x: A | Null): Nullable[A] = x
10+
11+
def some[A <: AnyRef](x: A): Nullable[A] = x
12+
def none: Nullable[Nothing] = null
13+
14+
extension [A <: AnyRef](x: Nullable[A])
15+
def isEmpty: Boolean = x == null
16+
def get: A | Null = x
17+
18+
extension [A <: AnyRef, B <: AnyRef](x: Nullable[A])
19+
def flatMap(f: A => Nullable[B]): Nullable[B] =
20+
if (x == null) null
21+
else f(x)
22+
23+
def map(f: A => B): Nullable[B] = x.flatMap(f)
24+
25+
def test1 =
26+
val s1: Nullable[String] = Nullable("hello")
27+
val s2: Nullable[String] = "world"
28+
val s3: Nullable[String] = Nullable.none
29+
val s4: Nullable[String] = null
30+
31+
s1.isEmpty
32+
s1.flatMap((x) => true)
33+
34+
assert(s2 != null)
35+
}
36+
37+
def test2 =
38+
import Nullables._
39+
40+
val s1: Nullable[String] = Nullable("hello")
41+
val s2: Nullable[String] = Nullable.none
42+
val s3: Nullable[String] = null // error: don't leak nullable union
43+
44+
s1.isEmpty
45+
s1.flatMap((x) => Nullable(true))
46+
47+
assert(s2 == null) // error
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import scala.language.unsafeNulls
2+
3+
def test1 =
4+
val s: String = ???
5+
s match
6+
case _: String =>
7+
// under unsafeNulls, we should not get Match case Unreachable Warning
8+
case null => // ok
9+
10+
def test2 =
11+
val s: String | Null = ???
12+
s match
13+
case _: String =>
14+
case null =>

tests/explicit-nulls/pos/opaque-nullable.scala

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Testing relaxed overriding check for explicit nulls.
2+
// The relaxed check is only enabled if one of the members is Java defined.
3+
4+
import java.util.Comparator
5+
6+
class C1[T <: AnyRef] extends Ordering[T]:
7+
override def compare(o1: T, o2: T): Int = 0
8+
9+
// The following overriding is not allowed, because `compare`
10+
// has already been declared in Scala class `Ordering`.
11+
// class C2[T <: AnyRef] extends Ordering[T]:
12+
// override def compare(o1: T | Null, o2: T | Null): Int = 0
13+
14+
class D1[T <: AnyRef] extends Comparator[T]:
15+
override def compare(o1: T, o2: T): Int = 0
16+
17+
class D2[T <: AnyRef] extends Comparator[T]:
18+
override def compare(o1: T | Null, o2: T | Null): Int = 0
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
def test1 =
2+
val s: String = ???
3+
s match
4+
case _: String =>
5+
case null => // error: Values of types Null and String cannot be compared
6+
7+
def test2 =
8+
val s: String | Null = ???
9+
s match
10+
case _: String =>
11+
case null =>

tests/neg/i14386.scala

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// scalac: -Werror
2+
def logLevelDetail(level: Int): String =
3+
s"""$level
4+
5+
// the following line is indented using [tab][tab]
6+
Sets the global logging level to $level.
7+
"""
8+
/* was 2 errors with carets as shown
9+
| ^ ^
10+
| Incompatible combinations of tabs and spaces in indentation prefixes.
11+
| Previous indent : 3 spaces
12+
| Latest indent : 2 tabs
13+
*/
14+
15+
def log(level: Int, msg: String): String =
16+
s"""
17+
$level
18+
prefixed $level suffixed
19+
"""
20+
/*
21+
^ ^
22+
Incompatible combinations of tabs and spaces in indentation prefixes.
23+
Previous indent : 2 tabs
24+
Latest indent : 2 space
25+
*/
26+
27+
// normal mixed tabs errors as a baseline
28+
def g =
29+
42
30+
+ 17 // error
31+
32+
def p() =
33+
println("hello")
34+
println("world") // error
35+
/*
36+
| Incompatible combinations of tabs and spaces in indentation prefixes.
37+
| Previous indent : 4 spaces
38+
| Latest indent : 1 tab
39+
*/
40+
41+
def braced() =
42+
s"""begin
43+
${
44+
val level = 10
45+
val msg = "hello, world" // error he lets me off with a warning
46+
log(level, msg) // error
47+
}
48+
end"""

0 commit comments

Comments
 (0)