diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index b435baba23f1..9b2a8d44ef2e 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -433,6 +433,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case SingletonTypeTree(ref) => Checking.checkRealizable(ref.tpe, ref.srcPos) super.transform(tree) + case tree: TypeBoundsTree => + val TypeBoundsTree(lo, hi, alias) = tree + if !alias.isEmpty then + val bounds = TypeBounds(lo.tpe, hi.tpe) + if !bounds.contains(alias.tpe) then + report.error(em"type ${alias.tpe} outside bounds $bounds", tree.srcPos) + super.transform(tree) case tree: TypeTree => tree.withType( tree.tpe match { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 9e76d57c763c..79a4e9afbc7f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2164,10 +2164,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val alias1 = typed(alias) val lo2 = if (lo1.isEmpty) typed(untpd.TypeTree(defn.NothingType)) else lo1 val hi2 = if (hi1.isEmpty) typed(untpd.TypeTree(defn.AnyType)) else hi1 - if !alias1.isEmpty then - val bounds = TypeBounds(lo2.tpe, hi2.tpe) - if !bounds.contains(alias1.tpe) then - report.error(em"type ${alias1.tpe} outside bounds $bounds", tree.srcPos) assignType(cpy.TypeBoundsTree(tree)(lo2, hi2, alias1), lo2, hi2, alias1) def typedBind(tree: untpd.Bind, pt: Type)(using Context): Tree = { diff --git a/tests/neg/i8337.scala b/tests/neg/i8337.scala index 7955c471fb70..6e42b96c2855 100644 --- a/tests/neg/i8337.scala +++ b/tests/neg/i8337.scala @@ -1,6 +1,6 @@ trait Foo[F <: Foo[F]] class Bar extends Foo[Bar] -object Q { // error: recursion limit exceeded - opaque type X <: Foo[X] = Bar // error: out of bounds // error +object Q { // error: cyclic reference + opaque type X <: Foo[X] = Bar // error: cyclic reference } \ No newline at end of file diff --git a/tests/neg/opaque-bounds-1.scala b/tests/neg/opaque-bounds-1.scala new file mode 100644 index 000000000000..e05cd56ae71c --- /dev/null +++ b/tests/neg/opaque-bounds-1.scala @@ -0,0 +1,13 @@ +abstract class Test { + opaque type FlagSet = Int + + opaque type Flag <: FlagSet = String // error: type String outside bounds <: Test.this.FlagSet + + object Flag { + def make(s: String): Flag = s + } + + val f: Flag = Flag.make("hello") + val g: FlagSet = f + +} \ No newline at end of file diff --git a/tests/neg/opaque-bounds.scala b/tests/neg/opaque-bounds.scala index 3eb03117e469..c39f184e2008 100644 --- a/tests/neg/opaque-bounds.scala +++ b/tests/neg/opaque-bounds.scala @@ -2,7 +2,7 @@ class Test { // error: class Test cannot be instantiated opaque type FlagSet = Int - opaque type Flag <: FlagSet = String // error: type String outside bounds <: Test.this.FlagSet + opaque type Flag <: FlagSet = String object Flag { def make(s: String): Flag = s diff --git a/tests/pos/recursive-opaques.scala b/tests/pos/recursive-opaques.scala new file mode 100644 index 000000000000..280d3854d4ea --- /dev/null +++ b/tests/pos/recursive-opaques.scala @@ -0,0 +1,12 @@ +object Syms: + import SymDs.* + opaque type Symbol <: AnyRef + = SymDenotation + opaque type ClassSymbol <: Symbol + = ClassDenotation + +object SymDs: + import Syms.* + class SymDenotation(sym: Symbol) + class ClassDenotation(sym: Symbol) extends SymDenotation(sym) +