Skip to content

Commit 4f04826

Browse files
committed
Modify upper bounds from tasty and class
1 parent 1e56187 commit 4f04826

File tree

8 files changed

+55
-16
lines changed

8 files changed

+55
-16
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,11 @@ class CheckRealizable(using Context) {
116116
case _: SingletonType | NoPrefix =>
117117
Realizable
118118
case tp =>
119+
// TODO
120+
// check the realizability of a special AndType
119121
def checkAndType(x: TermRef, y: Type) =
120122
(realizability(x) eq Realizable) && (y <:< x.widen)
121-
val isStableAndType = tp match {
123+
val isRealizableAndType = tp match {
122124
case AndType(tr: TermRef, tp1) =>
123125
checkAndType(tr, tp1)
124126
case AndType(tp1, tr: TermRef) =>
@@ -132,7 +134,7 @@ class CheckRealizable(using Context) {
132134
case tp: OrType => isConcrete(tp.tp1) && isConcrete(tp.tp2)
133135
case _ => false
134136
}
135-
if isStableAndType then Realizable
137+
if isRealizableAndType then Realizable
136138
else if !isConcrete(tp) then NotConcrete
137139
else boundsRealizability(tp).andAlso(memberRealizability(tp))
138140
}

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -648,11 +648,6 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
648648
tpnme.WILDCARD
649649
case tp: WildcardType =>
650650
sigName(tp.optBounds)
651-
case OrNull(tp) =>
652-
// If explicit nulls is enabled and the type is nullable union,
653-
// we need to strip nulls before computing the signiture name.
654-
// For example, the correct name of `String | Null` is `String` instead of `Object`.
655-
sigName(tp)
656651
case _ =>
657652
val erasedTp = this(tp)
658653
assert(erasedTp ne tp, tp)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ object Types {
170170
case tp: ExprType => tp.resultType.isStable
171171
case tp: AnnotatedType => tp.parent.isStable
172172
case tp: AndType =>
173+
// if one side is stable and another side is realizable or a subtype,
174+
// then the AndType is stable
173175
def checkAndStable(x: Type, y: Type) =
174176
x.isStable && ((realizability(y) eq Realizable) || y <:< x.widen)
175177
checkAndStable(tp.tp1, tp.tp2) || checkAndStable(tp.tp2, tp.tp1)
@@ -3125,7 +3127,7 @@ object Types {
31253127
*/
31263128
object OrNull {
31273129
def apply(tp: Type)(using Context) =
3128-
OrType(tp, defn.NullType, soft = false)
3130+
if tp.isNullType then tp else OrType(tp, defn.NullType, soft = false)
31293131
def unapply(tp: Type)(using Context): Option[Type] =
31303132
if ctx.explicitNulls then
31313133
val tp1 = tp.stripNull

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import util.SourceFile
2929
import ast.{TreeTypeMap, Trees, tpd, untpd}
3030
import Trees._
3131
import Decorators._
32+
import NullOpsDecorator._
3233
import transform.SymUtils._
3334

3435
import dotty.tools.tasty.{TastyBuffer, TastyReader}
@@ -362,7 +363,12 @@ class TreeUnpickler(reader: TastyReader,
362363
if nothingButMods(end) then
363364
if lo.isMatch then MatchAlias(readVariances(lo))
364365
else TypeAlias(readVariances(lo))
365-
else TypeBounds(lo, readVariances(readType()))
366+
else
367+
val hi0 = readVariances(readType())
368+
val hi =
369+
if ctx.explicitNulls && lo.isNullType && hi0.isNullableAfterErasure
370+
then OrNull(hi0) else hi0
371+
TypeBounds(lo, hi)
366372
case ANNOTATEDtype =>
367373
AnnotatedType(readType(), Annotation(readTerm()))
368374
case ANDtype =>
@@ -1239,7 +1245,10 @@ class TreeUnpickler(reader: TastyReader,
12391245
MatchTypeTree(bound, scrut, readCases(end))
12401246
case TYPEBOUNDStpt =>
12411247
val lo = readTpt()
1242-
val hi = if currentAddr == end then lo else readTpt()
1248+
val hi0 = if currentAddr == end then lo else readTpt()
1249+
val hi =
1250+
if ctx.explicitNulls && lo.tpe.isNullType && hi0.tpe.isNullableAfterErasure
1251+
then TypeTree(OrNull(hi0.tpe)) else hi0
12431252
val alias = if currentAddr == end then EmptyTree else readTpt()
12441253
TypeBoundsTree(lo, hi, alias)
12451254
case HOLE =>
@@ -1478,4 +1487,4 @@ object TreeUnpickler {
14781487
final val AllDefs = 2 // add everything
14791488

14801489
class TreeWithoutOwner extends Exception
1481-
}
1490+
}

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import PickleBuffer._
2323
import PickleFormat._
2424
import Decorators._
2525
import TypeApplications._
26+
import NullOpsDecorator._
2627
import classfile.ClassfileParser
2728
import scala.collection.mutable
2829
import scala.collection.mutable.ListBuffer
@@ -769,7 +770,12 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
769770
else if (sym.typeParams.nonEmpty) tycon.EtaExpand(sym.typeParams)
770771
else tycon
771772
case TYPEBOUNDStpe =>
772-
TypeBounds(readTypeRef(), readTypeRef())
773+
val lo = readTypeRef()
774+
val hi0 = readTypeRef()
775+
val hi =
776+
if ctx.explicitNulls && lo.isNullType && hi0.isNullableAfterErasure
777+
then OrNull(hi0) else hi0
778+
TypeBounds(lo, hi)
773779
case REFINEDtpe =>
774780
val clazz = readSymbolRef().asClass
775781
val decls = symScope(clazz)
@@ -1247,7 +1253,10 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
12471253

12481254
case TYPEBOUNDStree =>
12491255
val lo = readTreeRef()
1250-
val hi = readTreeRef()
1256+
val hi0 = readTreeRef()
1257+
val hi =
1258+
if ctx.explicitNulls && lo.tpe.isNullType && hi0.tpe.isNullableAfterErasure
1259+
then TypeTree(OrNull(hi0.tpe)) else hi0
12511260
TypeBoundsTree(lo, hi)
12521261

12531262
case EXISTENTIALTYPEtree =>
@@ -1309,4 +1318,4 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
13091318
case other =>
13101319
errorBadSignature("expected an TypeDef (" + other + ")")
13111320
}
1312-
}
1321+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ object Implicits:
334334
}
335335

336336
/** The implicit references that are eligible for type `tp`. */
337-
def eligible(tp: Type, enableUnsafeNulls: Boolean = false): List[Candidate] =
337+
def eligible(tp: Type, enableUnsafeNulls: Boolean): List[Candidate] =
338338
if tp.hash == NotCached then
339339
Stats.record(i"compute eligible not cached ${tp.getClass}")
340340
Stats.record(i"compute eligible not cached")

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ trait ImportSuggestions:
157157
// are in the implicit scope of `pt`.
158158
val alreadyAvailableCandidates: Set[Symbol] = {
159159
val wildProto = wildApprox(pt)
160-
val contextualCandidates = ctx.implicits.eligible(wildProto)
160+
val contextualCandidates = ctx.implicits.eligible(wildProto, ctx.mode.is(Mode.UnsafeNullConversion))
161161
val implicitScopeCandidates = ctx.run.implicitScope(wildProto).eligible
162162
val allCandidates = contextualCandidates ++ implicitScopeCandidates
163163
allCandidates.map(_.implicitRef.underlyingRef.symbol).toSet

tests/explicit-nulls/neg/bounds.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
val x1: String = ???
2+
val x2: String | Null = ???
3+
4+
// T has to be nullable type
5+
def f1[T >: Null <: AnyRef | Null](x: T): T = x
6+
7+
// Null is no longer a subtype of AnyRef, impossible to apply this method directly.
8+
// We can bypass this restriction by importing unsafeNulls.
9+
def f2[T >: Null <: AnyRef](x: T): T = x
10+
11+
def nullOf[T >: Null <: AnyRef | Null]: T = null
12+
13+
def g = {
14+
f1(x1)
15+
f1(x2)
16+
17+
f2(x1) // error
18+
f2(x2) // error
19+
20+
val n1: String = nullOf // error
21+
val n3: String | Null = nullOf
22+
}

0 commit comments

Comments
 (0)