Skip to content

Fix #9717: Fix typed tree copier for Selects over Nothing #9856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 24, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
tree1.withTypeUnchecked(tree.tpe)
case _ =>
val tree2 = tree.tpe match {
case tpe: NamedType => tree1.withType(tpe.derivedSelect(qualifier.tpe.widenIfUnstable))
case tpe: NamedType =>
val qualType = qualifier.tpe.widenIfUnstable
if qualType.isBottomType then tree1.withTypeUnchecked(tree.tpe)
else tree1.withType(tpe.derivedSelect(qualType))
case _ => tree1.withTypeUnchecked(tree.tpe)
}
ConstFold(tree2)
Expand Down
16 changes: 9 additions & 7 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
true
}

private def isBottom(tp: Type) = tp.widen.isRef(NothingClass)

protected def gadtBounds(sym: Symbol)(using Context) = ctx.gadt.bounds(sym)
protected def gadtAddLowerBound(sym: Symbol, b: Type): Boolean = ctx.gadt.addBound(sym, b, isUpper = false)
protected def gadtAddUpperBound(sym: Symbol, b: Type): Boolean = ctx.gadt.addBound(sym, b, isUpper = true)
Expand Down Expand Up @@ -371,7 +373,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
thirdTry
case tp1: TypeParamRef =>
def flagNothingBound = {
if (!frozenConstraint && tp2.isRef(NothingClass) && state.isGlobalCommittable) {
if (!frozenConstraint && isBottom(tp2) && state.isGlobalCommittable) {
def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}"
if (Config.failOnInstantiationToNothing) assert(false, msg)
else report.log(msg)
Expand Down Expand Up @@ -479,7 +481,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
case _ => false
}) ||
narrowGADTBounds(tp2, tp1, approx, isUpper = false)) &&
{ tp1.isRef(NothingClass) || GADTusage(tp2.symbol) }
{ isBottom(tp1) || GADTusage(tp2.symbol) }
}
isSubApproxHi(tp1, info2.lo) || compareGADT || tryLiftedToThis2 || fourthTry

Expand All @@ -488,7 +490,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
if (cls2.isClass)
if (cls2.typeParams.isEmpty) {
if (cls2 eq AnyKindClass) return true
if (tp1.isRef(NothingClass)) return true
if (isBottom(tp1)) return true
if (tp1.isLambdaSub) return false
// Note: We would like to replace this by `if (tp1.hasHigherKind)`
// but right now we cannot since some parts of the standard library rely on the
Expand Down Expand Up @@ -1872,8 +1874,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
if (tp1 eq tp2) tp1
else if (!tp1.exists) tp2
else if (!tp2.exists) tp1
else if tp1.isAny && !tp2.isLambdaSub || tp1.isAnyKind || tp2.isRef(NothingClass) then tp2
else if tp2.isAny && !tp1.isLambdaSub || tp2.isAnyKind || tp1.isRef(NothingClass) then tp1
else if tp1.isAny && !tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp2
else if tp2.isAny && !tp1.isLambdaSub || tp2.isAnyKind || isBottom(tp1) then tp1
else tp2 match { // normalize to disjunctive normal form if possible.
case tp2: LazyRef =>
glb(tp1, tp2.ref)
Expand Down Expand Up @@ -1925,8 +1927,8 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
if (tp1 eq tp2) tp1
else if (!tp1.exists) tp1
else if (!tp2.exists) tp2
else if tp1.isAny && !tp2.isLambdaSub || tp1.isAnyKind || tp2.isRef(NothingClass) then tp1
else if tp2.isAny && !tp1.isLambdaSub || tp2.isAnyKind || tp1.isRef(NothingClass) then tp2
else if tp1.isAny && !tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp1
else if tp2.isAny && !tp1.isLambdaSub || tp2.isAnyKind || isBottom(tp1) then tp2
else
def mergedLub(tp1: Type, tp2: Type): Type = {
tp1.atoms match
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ object Types {
case _ => false
}

/** Is this type exactly Any (no vars, aliases, refinements etc allowed)? */
/** Is this type exactly Any (no vars, aliases, refinements etc allowed)? */
def isTopType(using Context): Boolean = this match {
case tp: TypeRef =>
tp.name == tpnme.Any && (tp.symbol eq defn.AnyClass)
Expand Down
4 changes: 4 additions & 0 deletions tests/pos/i9717/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// minimized facade
object Object {
def assign[T, U](target: T, source: U): T with U = js.native
}
4 changes: 4 additions & 0 deletions tests/pos/i9717/js.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// minimized scala.js
package object js {
def native: Nothing = ???
}
2 changes: 0 additions & 2 deletions tests/run-macros/tasty-extractors-3.check
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Any")

TypeRef(NoPrefix(), "T")

TypeRef(NoPrefix(), "T")

TypeBounds(TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "<root>")), "scala"), "Int"), TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "<root>")), "scala"), "Int"))

TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "<root>")), "scala"), "Int")
Expand Down