Skip to content
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
4 changes: 2 additions & 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,8 @@ 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)
if !ex.isInstanceOf[TypeError] then ex.printStackTrace()
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