Skip to content

Commit 1e56187

Browse files
committed
Fix typo and move logic ops to next line
1 parent 9599411 commit 1e56187

File tree

6 files changed

+47
-39
lines changed

6 files changed

+47
-39
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ object NullOpsDecorator {
8282

8383
/** Can we convert a tree with type `self` to type `pt` unsafely.
8484
*/
85-
def isUnsafelyConvertable(pt: Type, relaxedSubtype: Boolean = false)(using Context): Boolean =
85+
def isUnsafelyConvertible(pt: Type, relaxedSubtype: Boolean = false)(using Context): Boolean =
8686
self.isUnsafelyNulltoAnyRef(pt) || self.isUnsafeSubtype(pt, relaxedSubtype)
8787
}
8888
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,9 @@ object ErrorReporting {
151151
case _ => Nil
152152
if foundWithoutNull then
153153
i""".
154-
|Since explicit-nulls is enabled, ${qualType.widen} could have null value during runtime.
155-
|If you want to select ${tree.name} without checking the nullity,
154+
|Since explicit-nulls is enabled, the selection is rejected because
155+
|${qualType.widen} could be null at runtime.
156+
|If you want to select ${tree.name} without checking for a null value,
156157
|insert a .nn before .${tree.name} or import scala.language.unsafeNulls."""
157158
else if qualType.derivesFrom(defn.DynamicClass) then
158159
"\npossible cause: maybe a wrong Dynamic method signature?"

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,8 @@ object Implicits:
306306
val refs: List[ImplicitRef],
307307
val outerImplicits: ContextualImplicits,
308308
isImport: Boolean)(initctx: Context) extends ImplicitRefs(initctx) {
309-
private val eligibleCache = EqHashMap[Type, List[Candidate]]()
310-
private val eligibleCacheUnsafeNulls = EqHashMap[Type, List[Candidate]]()
309+
private var eligibleCache: EqHashMap[Type, List[Candidate]] = null
310+
private var eligibleCacheUnsafeNulls: EqHashMap[Type, List[Candidate]] = null
311311

312312
/** The level increases if current context has a different owner or scope than
313313
* the context of the next-outer ImplicitRefs. This is however disabled under
@@ -335,7 +335,19 @@ object Implicits:
335335

336336
/** The implicit references that are eligible for type `tp`. */
337337
def eligible(tp: Type, enableUnsafeNulls: Boolean = false): List[Candidate] =
338-
def searchWithCache(cache: EqHashMap[Type, List[Candidate]]) = {
338+
if tp.hash == NotCached then
339+
Stats.record(i"compute eligible not cached ${tp.getClass}")
340+
Stats.record(i"compute eligible not cached")
341+
computeEligible(tp, enableUnsafeNulls)
342+
else
343+
val cache = if enableUnsafeNulls then
344+
if eligibleCacheUnsafeNulls == null then
345+
eligibleCacheUnsafeNulls = EqHashMap[Type, List[Candidate]]()
346+
eligibleCacheUnsafeNulls
347+
else
348+
if eligibleCache == null then
349+
eligibleCache = EqHashMap[Type, List[Candidate]]()
350+
eligibleCache
339351
val eligibles = cache.lookup(tp)
340352
if eligibles != null then
341353
Stats.record("cached eligible")
@@ -346,24 +358,16 @@ object Implicits:
346358
val result = computeEligible(tp, enableUnsafeNulls)
347359
cache(tp) = result
348360
result
349-
}
350-
if tp.hash == NotCached then
351-
Stats.record(i"compute eligible not cached ${tp.getClass}")
352-
Stats.record(i"compute eligible not cached")
353-
computeEligible(tp, enableUnsafeNulls)
354-
else if enableUnsafeNulls then
355-
searchWithCache(eligibleCacheUnsafeNulls)
356-
else
357-
searchWithCache(eligibleCache)
358361

359362
private def computeEligible(tp: Type, enableUnsafeNulls: Boolean): List[Candidate] = /*>|>*/ trace(i"computeEligible $tp in $refs%, %", implicitsDetailed) /*<|<*/ {
360363
if (monitored) record(s"check eligible refs in irefCtx", refs.length)
361-
val c = if enableUnsafeNulls then ctx.addMode(Mode.UnsafeNullConversion) else ctx
362-
val ownEligible = filterMatching(tp)(using c)
364+
val ownEligible = inContext(if enableUnsafeNulls then ctx.addMode(Mode.UnsafeNullConversion) else ctx) {
365+
filterMatching(tp)
366+
}
363367
if (isOuterMost) ownEligible
364-
else if ownEligible.isEmpty then outerImplicits.eligible(tp)
368+
else if ownEligible.isEmpty then outerImplicits.eligible(tp, enableUnsafeNulls)
365369
else
366-
val outerEligible = outerImplicits.eligible(tp)
370+
val outerEligible = outerImplicits.eligible(tp, enableUnsafeNulls)
367371
if outerEligible.isEmpty then ownEligible
368372
else
369373
val shadowed = ownEligible.map(_.ref.implicitName).toSet
@@ -1310,7 +1314,7 @@ trait Implicits:
13101314

13111315
/** All available implicits, without ranking */
13121316
def allImplicits: Set[TermRef] = {
1313-
val contextuals = ctx.implicits.eligible(wildProto).map(tryImplicit(_, contextual = true))
1317+
val contextuals = ctx.implicits.eligible(wildProto, ctx.mode.is(Mode.UnsafeNullConversion)).map(tryImplicit(_, contextual = true))
13141318
val inscope = implicitScope(wildProto).eligible.map(tryImplicit(_, contextual = false))
13151319
(contextuals.toSet ++ inscope).collect {
13161320
case success: SearchSuccess => success.ref

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,29 @@ object ProtoTypes {
3939
def isCompatible(tp: Type, pt: Type)(using Context): Boolean =
4040
val tpw = tp.widenExpr
4141
val ptw = pt.widenExpr
42-
(tpw relaxed_<:< ptw) ||
43-
// If unsafeNulls is enabled, we relax the condition by
44-
// striping all nulls from the types before subtype check.
45-
Nullables.convertUnsafeNulls && tpw.isUnsafelyConvertable(ptw, true) ||
46-
viewExists(tp, pt)
42+
(tpw relaxed_<:< ptw)
43+
// If unsafeNulls is enabled, we relax the condition by
44+
// striping all nulls from the types before subtype check.
45+
|| Nullables.convertUnsafeNulls && tpw.isUnsafelyConvertible(ptw, true)
46+
|| viewExists(tp, pt)
4747

4848
/** Like isCompatibe, but using a subtype comparison with necessary eithers
4949
* that don't unnecessarily truncate the constraint space, returning false instead.
5050
*/
5151
def necessarilyCompatible(tp: Type, pt: Type)(using Context): Boolean =
5252
val tpw = tp.widenExpr
5353
val ptw = pt.widenExpr
54-
necessarySubType(tpw, ptw) || tpw.isValueSubType(ptw) ||
55-
Nullables.convertUnsafeNulls && {
54+
necessarySubType(tpw, ptw)
55+
|| tpw.isValueSubType(ptw)
56+
|| Nullables.convertUnsafeNulls && {
5657
// See comments in `isCompatible`
5758
val tpwsn = tpw.stripAllNulls
5859
val ptwsn = ptw.stripAllNulls
59-
necessarySubType(tpwsn, ptwsn) || tpwsn.isValueSubType(ptwsn) ||
60-
tpwsn.isUnsafelyNulltoAnyRef(ptwsn)
61-
} ||
62-
viewExists(tp, pt)
60+
necessarySubType(tpwsn, ptwsn)
61+
|| tpwsn.isValueSubType(ptwsn)
62+
|| tpwsn.isUnsafelyNulltoAnyRef(ptwsn)
63+
}
64+
|| viewExists(tp, pt)
6365

6466
/** Test compatibility after normalization.
6567
* Do this in a fresh typerstate unless `keepConstraint` is true.

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3474,9 +3474,9 @@ class Typer extends Namer
34743474
val pt1 = if ctx.explicitNulls then pt.stripNull else pt
34753475
pt1 match {
34763476
case SAMType(sam)
3477-
if wtp <:< sam.toFunctionType() ||
3478-
(Nullables.convertUnsafeNulls &&
3479-
wtp.stripAllNulls <:< sam.toFunctionType().stripAllNulls) =>
3477+
if wtp <:< sam.toFunctionType()
3478+
|| (Nullables.convertUnsafeNulls
3479+
&& wtp.stripAllNulls <:< sam.toFunctionType().stripAllNulls) =>
34803480
// was ... && isFullyDefined(pt, ForceDegree.flipBottom)
34813481
// but this prevents case blocks from implementing polymorphic partial functions,
34823482
// since we do not know the result parameter a priori. Have to wait until the
@@ -3549,8 +3549,9 @@ class Typer extends Namer
35493549

35503550
def tryUnsafeNullConver(fail: => Tree)(using Context): Tree =
35513551
// If explicitNulls and unsafeNulls are enabled, and
3552-
if ctx.mode.is(Mode.UnsafeNullConversion) && pt.isValueType &&
3553-
treeTpe.isUnsafelyConvertable(pt)
3552+
if ctx.mode.is(Mode.UnsafeNullConversion)
3553+
&& pt.isValueType
3554+
&& treeTpe.isUnsafelyConvertible(pt)
35543555
then tree.cast(pt)
35553556
else fail
35563557

@@ -3573,8 +3574,8 @@ class Typer extends Namer
35733574
if ctx.mode.is(Mode.ImplicitsEnabled) && tree.typeOpt.isValueType then
35743575
if pt.isRef(defn.AnyValClass) || pt.isRef(defn.ObjectClass) then
35753576
// We want to allow `null` to `AnyRef` if UnsafeNullConversion is enabled
3576-
if !(ctx.mode.is(Mode.UnsafeNullConversion) &&
3577-
treeTpe.isUnsafelyConvertable(pt)) then
3577+
if !(ctx.mode.is(Mode.UnsafeNullConversion)
3578+
&& treeTpe.isUnsafelyConvertible(pt)) then
35783579
report.error(em"the result of an implicit conversion must be more specific than $pt", tree.srcPos)
35793580
tree.cast(pt)
35803581
else

docs/docs/internals/explicit-nulls.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ There are some utility functions for nullable types in `NullOpsDecorator.scala`
3535
ones (as `stripNull` does).
3636
- `isNullableUnion` determines whether `this` is a nullable union.
3737
- `isNullableAfterErasure` determines whether `this` type can have `null` value after erasure.
38-
- `isUnsafelyConvertable` determines whether we can convert `this` type to `pt` unsafely if we ignore `Null` type.
38+
- `isUnsafelyConvertible` determines whether we can convert `this` type to `pt` unsafely if we ignore `Null` type.
3939

4040
Within `Types.scala`, we also defined an extractor `OrNull` to extract the non-nullable part of a nullable unions .
4141

0 commit comments

Comments
 (0)