Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/backend/jvm/CodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ class CodeGen(val int: DottyBackendInterface, val primitives: DottyPrimitives)(
case ex: InterruptedException => throw ex
case ex: CompilationUnit.SuspendException => throw ex
case ex: Throwable =>
ex.printStackTrace()
report.error(s"Error while emitting ${unit.source}\n${ex.getMessage}", NoSourcePosition)
report.error(s"Error while emitting ${unit.source}\n${ex.getMessage}", cd.sourcePos)


def genTastyAndSetAttributes(claszSymbol: Symbol, store: ClassNode): Unit =
Expand Down
14 changes: 14 additions & 0 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -865,9 +865,23 @@ object SymDenotations {
* and is the denoting symbol also different from `Null` or `Nothing`?
* @note erroneous classes are assumed to derive from all other classes
* and all classes derive from them.
* @note may return a false negative when `this.info.isInstanceOf[TempClassInfo]`.
*/
def derivesFrom(base: Symbol)(using Context): Boolean = false

/** Could `this` derive from `base` now or in the future.
* For concistency with derivesFrom, The info is only forced when this is a ClassDenotation.
* If the info is a TempClassInfo then the baseClassSet may be temporarily approximated as empty.
* This is problematic when stability of `!derivesFrom(base)` is assumed for soundness,
* e.g., in `TypeComparer#provablyDisjointClasses`.
* @note may return a false positive when `this.info.isInstanceOf[TempClassInfo]`.
*/
final def mayDeriveFrom(base: Symbol)(using Context): Boolean =
this.isInstanceOf[ClassDenotation] && (info.isInstanceOf[TempClassInfo] || derivesFrom(base))

final def derivesFrom(base: Symbol, defaultIfUnknown: Boolean)(using Context): Boolean =
if defaultIfUnknown/*== true*/ then mayDeriveFrom(base) else derivesFrom(base)

/** Is this a Scala or Java annotation ? */
def isAnnotation(using Context): Boolean =
isClass && (derivesFrom(defn.AnnotationClass) || is(JavaAnnotation))
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3131,9 +3131,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
* unique value derives from the class.
*/
case (tp1: SingletonType, tp2) =>
!tp1.derivesFrom(tp2.classSymbol)
!tp1.derivesFrom(tp2.classSymbol, defaultIfUnknown = true)
case (tp1, tp2: SingletonType) =>
!tp2.derivesFrom(tp1.classSymbol)
!tp2.derivesFrom(tp1.classSymbol, defaultIfUnknown = true)

/* Now both sides are possibly-parameterized class types `p.C[Ts]` and `q.D[Us]`.
*
Expand Down Expand Up @@ -3189,7 +3189,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
val cls2BaseClassSet = SymDenotations.BaseClassSet(cls2.classDenot.baseClasses)
val commonBaseClasses = cls1.classDenot.baseClasses.filter(cls2BaseClassSet.contains(_))
def isAncestorOfOtherBaseClass(cls: ClassSymbol): Boolean =
commonBaseClasses.exists(other => (other ne cls) && other.derivesFrom(cls))
commonBaseClasses.exists(other => (other ne cls) && other.mayDeriveFrom(cls))
val result = commonBaseClasses.exists { baseClass =>
!isAncestorOfOtherBaseClass(baseClass) && isBaseTypeWithDisjointArguments(baseClass, innerPending)
}
Expand Down Expand Up @@ -3230,7 +3230,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
.filter(child => child.exists && child != cls)

def eitherDerivesFromOther(cls1: Symbol, cls2: Symbol): Boolean =
cls1.derivesFrom(cls2) || cls2.derivesFrom(cls1)
cls1.mayDeriveFrom(cls2) || cls2.mayDeriveFrom(cls1)

def smallestNonTraitBase(cls: Symbol): Symbol =
val classes = if cls.isClass then cls.asClass.baseClasses else cls.info.classSymbols
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -270,15 +270,15 @@ object Types extends TypeUtils {
/** True if this type is an instance of the given `cls` or an instance of
* a non-bottom subclass of `cls`.
*/
final def derivesFrom(cls: Symbol)(using Context): Boolean = {
final def derivesFrom(cls: Symbol, defaultIfUnknown: Boolean = false)(using Context): Boolean = {
def isLowerBottomType(tp: Type) =
tp.isBottomType
&& (tp.hasClassSymbol(defn.NothingClass)
|| cls != defn.NothingClass && !cls.isValueClass)
def loop(tp: Type): Boolean = try tp match
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass) sym.derivesFrom(cls) else loop(tp.superType)
if (sym.isClass) sym.derivesFrom(cls, defaultIfUnknown) else loop(tp.superType)
case tp: AppliedType =>
tp.superType.derivesFrom(cls)
case tp: MatchType =>
Expand Down
31 changes: 31 additions & 0 deletions tests/neg/i17132.min.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- Error: tests/neg/i17132.min.scala:4:7 -------------------------------------------------------------------------------
4 |class Q[T <: P[Any]] extends P[R[T]] // error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Recursion limit exceeded.
| Maybe there is an illegal cyclic reference?
| If that's not the case, you could also try to increase the stacksize using the -Xss JVM option.
| For the unprocessed stack trace, compile with -Xno-enrich-error-messages.
| A recurring operation is (inner to outer):
|
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| ...
|
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type t match ...
| reduce type T match ...
9 changes: 9 additions & 0 deletions tests/neg/i17132.min.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

class P[T]
//class Q[T] extends P[R[T]] // ok
class Q[T <: P[Any]] extends P[R[T]] // error
//type Q[T <: P[Any]] <: P[R[T]] // ok

type R[U] = U match
case Q[t] => R[t]
case P[t] => t
11 changes: 11 additions & 0 deletions tests/neg/i17132.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

sealed trait Transformation[T]

case object Count extends Transformation[Int]
case class MultiTransformation[T1 <: Transformation[?], T2 <: Transformation[?]](t1: T1, t2: T2) // error cyclic
extends Transformation[MultiTransformationResult[T1, T2]]

type MultiTransformationResult[T1 <: Transformation[?], T2 <: Transformation[?]] <: Tuple = (T1, T2) match {
case (Transformation[t], MultiTransformation[t1, t2]) => t *: MultiTransformationResult[t1, t2]
case (Transformation[t1], Transformation[t2]) => (t1, t2)
}
Loading