Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
val tree2: Select = tree.tpe match {
case tpe: NamedType =>
val qualType = qualifier.tpe.widenIfUnstable
if qualType.isBottomType then tree1.withTypeUnchecked(tree.tpe)
if qualType.isNothingType then tree1.withTypeUnchecked(tree.tpe)
else tree1.withType(tpe.derivedSelect(qualType))
case _ => tree1.withTypeUnchecked(tree.tpe)
}
Expand Down
8 changes: 7 additions & 1 deletion compiler/src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,11 @@ class TypeApplications(val self: Type) extends AnyVal {
case _ =>
if (self.derivesFrom(from)) {
def elemType(tp: Type): Type = tp.widenDealias match
case tp: AndOrType => tp.derivedAndOrType(elemType(tp.tp1), elemType(tp.tp2))
case tp: OrType =>
if defn.isBottomType(tp.tp1) then elemType(tp.tp2)
else if defn.isBottomType(tp.tp2) then elemType(tp.tp1)
else tp.derivedOrType(elemType(tp.tp1), elemType(tp.tp2))
case tp: AndType => tp.derivedAndType(elemType(tp.tp1), elemType(tp.tp2))
case _ => tp.baseType(from).argInfos.headOption.getOrElse(defn.NothingType)
val arg = elemType(self)
val arg1 = if (wildcardArg) TypeBounds.upper(arg) else arg
Expand Down Expand Up @@ -499,6 +503,8 @@ class TypeApplications(val self: Type) extends AnyVal {
def elemType(using Context): Type = self.widenDealias match {
case defn.ArrayOf(elemtp) => elemtp
case JavaArrayType(elemtp) => elemtp
case tp: OrType if defn.isBottomType(tp.tp1) => tp.tp2.elemType
case tp: OrType if defn.isBottomType(tp.tp2) => tp.tp1.elemType
case _ => self.baseType(defn.SeqClass).argInfos.headOption.getOrElse(NoType)
}
}
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2325,7 +2325,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
*/
def provablyEmpty(tp: Type): Boolean =
tp.dealias match {
case tp if tp.isBottomType => true
case tp if tp.isNothingType => true
case AndType(tp1, tp2) => provablyDisjoint(tp1, tp2)
case OrType(tp1, tp2) => provablyEmpty(tp1) && provablyEmpty(tp2)
case at @ AppliedType(tycon, args) =>
Expand Down
22 changes: 13 additions & 9 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,11 @@ object Types {
case tp: AndType =>
loop(tp.tp1) || loop(tp.tp2)
case tp: OrType =>
loop(tp.tp1) && loop(tp.tp2)
// If the type is `T | Null` or `T | Nothing`, and `T` derivesFrom the class,
// then the OrType derivesFrom the class. Otherwise, we need to check both sides
// derivesFrom the class.
if defn.isBottomType(tp.tp1) then loop(tp.tp2)
else loop(tp.tp1) && (defn.isBottomType(tp.tp2) || loop(tp.tp2))
case tp: JavaArrayType =>
cls == defn.ObjectClass
case _ =>
Expand All @@ -262,7 +266,7 @@ object Types {
}

/** Is this type exactly Nothing (no vars, aliases, refinements etc allowed)? */
def isBottomType(using Context): Boolean = this match {
def isNothingType(using Context): Boolean = this match {
case tp: TypeRef =>
tp.name == tpnme.Nothing && (tp.symbol eq defn.NothingClass)
case _ => false
Expand Down Expand Up @@ -2122,7 +2126,7 @@ object Types {
case arg: TypeBounds =>
val v = param.paramVarianceSign
val pbounds = param.paramInfo
if (v > 0 && pbounds.loBound.dealiasKeepAnnots.isBottomType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound))
if (v > 0 && pbounds.loBound.dealiasKeepAnnots.isNothingType) TypeAlias(arg.hiBound & rebase(pbounds.hiBound))
else if (v < 0 && pbounds.hiBound.dealiasKeepAnnots.isTopType) TypeAlias(arg.loBound | rebase(pbounds.loBound))
else arg recoverable_& rebase(pbounds)
case arg => TypeAlias(arg)
Expand Down Expand Up @@ -2285,7 +2289,7 @@ object Types {
if (base.isAnd == variance >= 0) tp1 & tp2 else tp1 | tp2
case _ =>
if (pre.termSymbol.is(Package)) argForParam(pre.select(nme.PACKAGE))
else if (pre.isBottomType) pre
else if (pre.isNothingType) pre
else NoType
}
}
Expand All @@ -2304,7 +2308,7 @@ object Types {
*/
def derivedSelect(prefix: Type)(using Context): Type =
if (prefix eq this.prefix) this
else if (prefix.isBottomType) prefix
else if (prefix.isNothingType) prefix
else {
if (isType) {
val res =
Expand Down Expand Up @@ -4288,7 +4292,7 @@ object Types {

/** For uninstantiated type variables: Is the lower bound different from Nothing? */
def hasLowerBound(using Context): Boolean =
!ctx.typerState.constraint.entry(origin).loBound.isBottomType
!ctx.typerState.constraint.entry(origin).loBound.isNothingType

/** For uninstantiated type variables: Is the upper bound different from Any? */
def hasUpperBound(using Context): Boolean =
Expand Down Expand Up @@ -5293,7 +5297,7 @@ object Types {
case _ =>
def propagate(lo: Type, hi: Type) =
range(derivedRefinedType(tp, parent, lo), derivedRefinedType(tp, parent, hi))
if (parent.isBottomType) parent
if (parent.isNothingType) parent
else info match {
case Range(infoLo: TypeBounds, infoHi: TypeBounds) =>
assert(variance == 0)
Expand Down Expand Up @@ -5386,7 +5390,7 @@ object Types {
case Range(lo, hi) =>
range(tp.derivedAnnotatedType(lo, annot), tp.derivedAnnotatedType(hi, annot))
case _ =>
if (underlying.isBottomType) underlying
if (underlying.isNothingType) underlying
else tp.derivedAnnotatedType(underlying, annot)
}
override protected def derivedWildcardType(tp: WildcardType, bounds: Type): WildcardType =
Expand Down Expand Up @@ -5634,7 +5638,7 @@ object Types {
else {
seen += tp
tp match {
case tp if tp.isTopType || tp.isBottomType =>
case tp if tp.isTopType || tp.isNothingType =>
cs
case tp: AppliedType =>
foldOver(cs + tp.typeSymbol, tp)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/interactive/Completion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ object Completion {
* considered.
*/
def addMemberCompletions(qual: Tree)(using Context): Unit =
if (!qual.tpe.widenDealias.isBottomType) {
if (!qual.tpe.widenDealias.isNothingType) {
addAccessibleMembers(qual.tpe)
if (!mode.is(Mode.Import) && !qual.tpe.isNullType)
// Implicit conversions do not kick in when importing
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ object ErrorReporting {
|Note that `${tree.name}` is treated as an infix operator in Scala 3.
|If you do not want that, insert a `;` or empty line in front
|or drop any spaces behind the operator."""
else if qualType.isBottomType then
else if qualType.isNothingType then
""
else
val add = suggestImports(
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,6 @@ class Typer extends Namer
if (ctx.mode.is(Mode.QuotedPattern)) pt.translateFromRepeated(toArray = false, translateWildcard = true)
else pt.translateFromRepeated(toArray = false, translateWildcard = true) |
pt.translateFromRepeated(toArray = true, translateWildcard = true)
val tpdExpr = typedExpr(tree.expr, ptArg)
val expr1 = typedExpr(tree.expr, ptArg)
val fromCls = if expr1.tpe.derivesFrom(defn.ArrayClass) then defn.ArrayClass else defn.SeqClass
val tpt1 = TypeTree(expr1.tpe.widen.translateToRepeated(fromCls)).withSpan(tree.tpt.span)
Expand Down
12 changes: 12 additions & 0 deletions tests/neg/repeatedArgs213.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,16 @@ class repeatedArgs {
Paths.get("Hello", ys: _*) // error: immutable.Seq expected, found Seq
Paths.get("Hello", zs: _*)
}

def test2(xs: immutable.Seq[String] | Null, ys: collection.Seq[String] | Null, zs: Array[String] | Null): Unit = {
bar("a", "b", "c")
bar(xs: _*)
bar(ys: _*) // error: immutable.Seq expected, found Seq
bar(zs: _*) // old-error: Remove (compiler generated) Array to Seq conversion in 2.13?

Paths.get("Hello", "World")
Paths.get("Hello", xs: _*)
Paths.get("Hello", ys: _*) // error: immutable.Seq expected, found Seq
Paths.get("Hello", zs: _*)
}
}
11 changes: 11 additions & 0 deletions tests/pos/repeatedArgs213.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,15 @@ class repeatedArgs {
val List(_, others: _*) = xs.toList // toList should not be needed, see #4790
val x: immutable.Seq[String] = others
}

def test2(xs: immutable.Seq[String] | Null): Unit = {
bar("a", "b", "c")
bar(xs: _*)

Paths.get("Hello", "World")
Paths.get("Hello", xs: _*)

val List(_, others: _*) = xs.toList // toList should not be needed, see #4790
val x: immutable.Seq[String] = others
}
}