Skip to content

Commit 9a59970

Browse files
committed
TypeErasure#apply: use WildcardType instead of null
As requested in the review, this is slightly shorter but means we have to be very careful to not accidentally forget to propagate a WildcardType to the top-level when computing signatures.
1 parent f6a9c94 commit 9a59970

File tree

1 file changed

+17
-19
lines changed

1 file changed

+17
-19
lines changed

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

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -596,10 +596,10 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
596596
*
597597
* If computing the erasure of T requires erasing a WildcardType or an
598598
* uninstantiated type variable, then an exception signaling an internal
599-
* error will be thrown, unless `inSigName` is set in which case `null`
599+
* error will be thrown, unless `inSigName` is set in which case WildcardType
600600
* will be returned.
601601
*
602-
* In all other situations, |T| will be non-null and computed as follow:
602+
* In all other situations, |T| will be computed as follow:
603603
* - For a refined type scala.Array+[T]:
604604
* - if T is Nothing or Null, []Object
605605
* - otherwise, if T <: Object, []|T|
@@ -631,7 +631,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
631631
* - For NoType or NoPrefix, the type itself.
632632
* - For any other type, exception.
633633
*/
634-
private def apply(tp: Type)(using Context): Type | Null =
634+
private def apply(tp: Type)(using Context): Type =
635635
val etp = tp match
636636
case _: ErasedValueType =>
637637
tp
@@ -655,7 +655,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
655655
case SuperType(thistpe, supertpe) =>
656656
val eThis = this(thistpe)
657657
val eSuper = this(supertpe)
658-
if eThis == null || eSuper == null then null
658+
if eThis.isInstanceOf[WildcardType] || eSuper.isInstanceOf[WildcardType] then WildcardType
659659
else SuperType(eThis, eSuper)
660660
case ExprType(rt) =>
661661
defn.FunctionType(0)
@@ -665,7 +665,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
665665
eraseErasedFunctionApply(refinedInfo)
666666
case tp: TypeVar if !tp.isInstantiated =>
667667
assert(inSigName, i"Cannot erase uninstantiated type variable $tp")
668-
null
668+
WildcardType
669669
case tp: TypeProxy =>
670670
this(tp.underlying)
671671
case tp @ AndType(tp1, tp2) =>
@@ -676,7 +676,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
676676
else
677677
val e1 = this(tp1)
678678
val e2 = this(tp2)
679-
if e1 == null || e2 == null then null
679+
if e1.isInstanceOf[WildcardType] || e2.isInstanceOf[WildcardType] then WildcardType
680680
else erasedGlb(e1, e2)
681681
case OrType(tp1, tp2) =>
682682
if isSymbol && sourceLanguage.isScala2 && ctx.settings.scalajs.value then
@@ -693,7 +693,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
693693
else
694694
val e1 = this(tp1)
695695
val e2 = this(tp2)
696-
if e1 == null || e2 == null then null
696+
if e1.isInstanceOf[WildcardType] || e2.isInstanceOf[WildcardType] then WildcardType
697697
else TypeComparer.orType(e1, e2, isErased = true)
698698
case tp: MethodType =>
699699
def paramErasure(tpToErase: Type) =
@@ -751,10 +751,10 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
751751
tp
752752
case tp: WildcardType =>
753753
assert(inSigName, i"Cannot erase wildcard type $tp")
754-
null
754+
WildcardType
755755
case tp if (tp `eq` NoType) || (tp `eq` NoPrefix) =>
756756
tp
757-
assert(etp != null || inSigName, i"Unexpected null erasure for $tp")
757+
assert(!etp.isInstanceOf[WildcardType] || inSigName, i"Unexpected WildcardType erasure for $tp")
758758
etp
759759

760760
/** Like translucentSuperType, but issue a fatal error if it does not exist. */
@@ -788,15 +788,15 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
788788
else
789789
try
790790
val eElem = erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)(elemtp)
791-
if eElem == null then null
791+
if eElem.isInstanceOf[WildcardType] then WildcardType
792792
else JavaArrayType(eElem)
793793
catch case ex: Throwable =>
794794
handleRecursive("erase array type", tp.show, ex)
795795
}
796796

797-
private def erasePair(tp: Type)(using Context): Type | Null = {
797+
private def erasePair(tp: Type)(using Context): Type = {
798798
val arity = tupleArity(tp)
799-
if arity == -2 then null // erasure depends on an uninstantiated type variable or WildcardType
799+
if arity == -2 then WildcardType // erasure depends on an uninstantiated type variable or WildcardType
800800
else if arity == -1 then defn.ProductClass.typeRef
801801
else if arity <= Definitions.MaxTupleArity then defn.TupleType(arity).nn
802802
else defn.TupleXXLClass.typeRef
@@ -827,7 +827,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
827827
case rt => MethodType(Nil, Nil, rt)
828828
case tp1 => this(tp1).nn
829829

830-
private def eraseDerivedValueClass(tp: Type)(using Context): Type | Null = {
830+
private def eraseDerivedValueClass(tp: Type)(using Context): Type = {
831831
val cls = tp.classSymbol.asClass
832832
val unbox = valueClassUnbox(cls)
833833
if unbox.exists then
@@ -837,7 +837,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
837837
// The underlying part of an ErasedValueType cannot be an ErasedValueType itself
838838
val erase = erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, isSymbol, inSigName)
839839
val erasedUnderlying = erase(underlying)
840-
if erasedUnderlying == null then return null
840+
if erasedUnderlying.isInstanceOf[WildcardType] then return WildcardType
841841

842842
// Ideally, we would just use `erasedUnderlying` as the erasure of `tp`, but to
843843
// be binary-compatible with Scala 2 we need two special cases for polymorphic
@@ -891,15 +891,14 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
891891

892892
/** The name of the type as it is used in `Signature`s.
893893
*
894-
* If `tp` is null, or if computing its erasure requires erasing a
894+
* If `tp` is WildcardType, or if computing its erasure requires erasing a
895895
* WildcardType or an uninstantiated type variable, then the special name
896896
* `tpnme.Uninstantiated` which is used to signal an underdefined signature
897897
* is used.
898898
*
899899
* Note: Need to ensure correspondence with erasure!
900900
*/
901-
private def sigName(tp: Type | Null)(using Context): TypeName = try
902-
if tp == null then return tpnme.Uninstantiated
901+
private def sigName(tp: Type)(using Context): TypeName = try
903902
tp match {
904903
case tp: TypeRef =>
905904
if (!tp.denot.exists)
@@ -913,7 +912,6 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
913912
}
914913
if (semiEraseVCs && isDerivedValueClass(sym)) {
915914
val erasedVCRef = eraseDerivedValueClass(tp)
916-
if erasedVCRef == null then return tpnme.Uninstantiated
917915
if (erasedVCRef.exists) return sigName(erasedVCRef)
918916
}
919917
if (defn.isSyntheticFunctionClass(sym))
@@ -960,7 +958,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
960958
tpnme.Uninstantiated
961959
case tp: ErrorType =>
962960
tpnme.ERROR
963-
case _ if tp eq NoType => // Can't write `case NoType` because of #18083.
961+
case NoType =>
964962
tpnme.ERROR
965963
case _ =>
966964
val erasedTp = this(tp)

0 commit comments

Comments
 (0)