diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 88714849587b..17d5cac7ce0b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -252,7 +252,7 @@ object desugar { if (meth1.mods.is(Inline)) meth1.tpt match { - case TypeBoundsTree(_, tpt1) => + case TypeBoundsTree(_, tpt1, _) => meth1 = cpy.DefDef(meth1)(tpt = tpt1) case tpt if !tpt.isEmpty && !meth1.rhs.isEmpty => meth1 = cpy.DefDef(meth1)(rhs = Typed(meth1.rhs, tpt)) @@ -684,7 +684,7 @@ object desugar { val mods = constr1.mods mods.is(Private) || (!mods.is(Protected) && mods.hasPrivateWithin) } - + /** Does one of the parameter's types (in the first param clause) * mention a preceding parameter? */ @@ -1156,7 +1156,8 @@ object desugar { val legalOpaque: MemberDefTest = { case TypeDef(_, rhs) => def rhsOK(tree: Tree): Boolean = tree match { - case _: TypeBoundsTree | _: Template => false + case bounds: TypeBoundsTree => !bounds.alias.isEmpty + case _: Template => false case LambdaTypeTree(_, body) => rhsOK(body) case _ => true } diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 2bc921f4c39d..4923b2ef0e6b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -690,8 +690,10 @@ object Trees { type ThisTree[-T >: Untyped] = ByNameTypeTree[T] } - /** >: lo <: hi */ - case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T])(implicit @constructorOnly src: SourceFile) + /** >: lo <: hi + * >: lo <: hi = alias for RHS of bounded opaque type + */ + case class TypeBoundsTree[-T >: Untyped] private[ast] (lo: Tree[T], hi: Tree[T], alias: Tree[T])(implicit @constructorOnly src: SourceFile) extends TypTree[T] { type ThisTree[-T >: Untyped] = TypeBoundsTree[T] } @@ -760,7 +762,8 @@ object Trees { /** mods class name template or * mods trait name template or * mods type name = rhs or - * mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) & (lo ne hi) + * mods type name >: lo <: hi, if rhs = TypeBoundsTree(lo, hi) or + * mods type name >: lo <: hi = rhs if rhs = TypeBoundsTree(lo, hi, alias) and opaque in mods */ case class TypeDef[-T >: Untyped] private[ast] (name: TypeName, rhs: Tree[T])(implicit @constructorOnly src: SourceFile) extends MemberDef[T] { @@ -811,8 +814,6 @@ object Trees { extends ProxyTree[T] { type ThisTree[-T >: Untyped] = Annotated[T] def forwardTo: Tree[T] = arg - override def disableOverlapChecks = true - // disable overlaps checks since the WithBounds annotation swaps type and annotation. } trait WithoutTypeOrPos[-T >: Untyped] extends Tree[T] { @@ -1151,9 +1152,9 @@ object Trees { case tree: ByNameTypeTree if (result eq tree.result) => tree case _ => finalize(tree, untpd.ByNameTypeTree(result)(sourceFile(tree))) } - def TypeBoundsTree(tree: Tree)(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = tree match { - case tree: TypeBoundsTree if (lo eq tree.lo) && (hi eq tree.hi) => tree - case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi)(sourceFile(tree))) + def TypeBoundsTree(tree: Tree)(lo: Tree, hi: Tree, alias: Tree)(implicit ctx: Context): TypeBoundsTree = tree match { + case tree: TypeBoundsTree if (lo eq tree.lo) && (hi eq tree.hi) && (alias eq tree.alias) => tree + case _ => finalize(tree, untpd.TypeBoundsTree(lo, hi, alias)(sourceFile(tree))) } def Bind(tree: Tree)(name: Name, body: Tree)(implicit ctx: Context): Bind = tree match { case tree: Bind if (name eq tree.name) && (body eq tree.body) => tree @@ -1304,8 +1305,8 @@ object Trees { cpy.MatchTypeTree(tree)(transform(bound), transform(selector), transformSub(cases)) case ByNameTypeTree(result) => cpy.ByNameTypeTree(tree)(transform(result)) - case TypeBoundsTree(lo, hi) => - cpy.TypeBoundsTree(tree)(transform(lo), transform(hi)) + case TypeBoundsTree(lo, hi, alias) => + cpy.TypeBoundsTree(tree)(transform(lo), transform(hi), transform(alias)) case Bind(name, body) => cpy.Bind(tree)(name, transform(body)) case Alternative(trees) => @@ -1428,8 +1429,8 @@ object Trees { this(this(this(x, bound), selector), cases) case ByNameTypeTree(result) => this(x, result) - case TypeBoundsTree(lo, hi) => - this(this(x, lo), hi) + case TypeBoundsTree(lo, hi, alias) => + this(this(this(x, lo), hi), alias) case Bind(name, body) => this(x, body) case Alternative(trees) => diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 21ce73ee9a97..b93c22208070 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -179,8 +179,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit ctx: Context): MatchTypeTree = ta.assignType(untpd.MatchTypeTree(bound, selector, cases), bound, selector, cases) - def TypeBoundsTree(lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = - ta.assignType(untpd.TypeBoundsTree(lo, hi), lo, hi) + def TypeBoundsTree(lo: Tree, hi: Tree, alias: Tree = EmptyTree)(implicit ctx: Context): TypeBoundsTree = + ta.assignType(untpd.TypeBoundsTree(lo, hi, alias), lo, hi, alias) def Bind(sym: Symbol, body: Tree)(implicit ctx: Context): Bind = ta.assignType(untpd.Bind(sym.name, body), sym) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index 0cea2c2160c0..d59683a50253 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -376,7 +376,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def LambdaTypeTree(tparams: List[TypeDef], body: Tree)(implicit src: SourceFile): LambdaTypeTree = new LambdaTypeTree(tparams, body) def MatchTypeTree(bound: Tree, selector: Tree, cases: List[CaseDef])(implicit src: SourceFile): MatchTypeTree = new MatchTypeTree(bound, selector, cases) def ByNameTypeTree(result: Tree)(implicit src: SourceFile): ByNameTypeTree = new ByNameTypeTree(result) - def TypeBoundsTree(lo: Tree, hi: Tree)(implicit src: SourceFile): TypeBoundsTree = new TypeBoundsTree(lo, hi) + def TypeBoundsTree(lo: Tree, hi: Tree, alias: Tree = EmptyTree)(implicit src: SourceFile): TypeBoundsTree = new TypeBoundsTree(lo, hi, alias) def Bind(name: Name, body: Tree)(implicit src: SourceFile): Bind = new Bind(name, body) def Alternative(trees: List[Tree])(implicit src: SourceFile): Alternative = new Alternative(trees) def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit src: SourceFile): UnApply = new UnApply(fun, implicits, patterns) diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index cc94f14988ba..38a0fe1ef40e 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -173,22 +173,6 @@ object Annotations { else None } - /** Extractor for WithBounds[T] annotations */ - object WithBounds { - def unapply(ann: Annotation)(implicit ctx: Context): Option[TypeBounds] = - if (ann.symbol == defn.WithBoundsAnnot) { - import ast.Trees._ - // We need to extract the type of the type tree in the New itself. - // The annotation's type has been simplified as the type of an expression, - // which means that `&` or `|` might have been lost. - // Test in pos/reference/opaque.scala - val Apply(TypeApply(Select(New(tpt), nme.CONSTRUCTOR), _), Nil) = ann.tree - val AppliedType(_, lo :: hi :: Nil) = tpt.tpe - Some(TypeBounds(lo, hi)) - } - else None - } - def makeSourceFile(path: String)(implicit ctx: Context): Annotation = apply(defn.SourceFileAnnot, Literal(Constant(path))) } diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 35349f6aa5c1..51eece14c4f2 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -784,7 +784,6 @@ class Definitions { @tu lazy val AnnotationDefaultAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.AnnotationDefault") @tu lazy val BodyAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.Body") @tu lazy val ChildAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.Child") - @tu lazy val WithBoundsAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.WithBounds") @tu lazy val CovariantBetweenAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.CovariantBetween") @tu lazy val ContravariantBetweenAnnot: ClassSymbol = ctx.requiredClass("scala.annotation.internal.ContravariantBetween") @tu lazy val DeprecatedAnnot: ClassSymbol = ctx.requiredClass("scala.deprecated") diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 2fae3e464abe..6081bd5a9686 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -11,6 +11,7 @@ import Scopes.Scope import dotty.tools.io.AbstractFile import Decorators.SymbolIteratorDecorator import ast._ +import ast.Trees.{LambdaTypeTree, TypeBoundsTree} import Trees.Literal import Variances.Variance import annotation.tailrec @@ -433,8 +434,9 @@ object SymDenotations { * * @param info Is assumed to be a (lambda-abstracted) right hand side TypeAlias * of the opaque type definition. + * @param rhs The right hand side tree of the type definition */ - def opaqueToBounds(info: Type)(given Context): Type = + def opaqueToBounds(info: Type, rhs: tpd.Tree)(given Context): Type = def setAlias(tp: Type) = def recur(self: Type): Unit = self match @@ -446,21 +448,19 @@ object SymDenotations { recur(owner.asClass.givenSelfType) end setAlias - def split(tp: Type): (Type, TypeBounds) = tp match - case AnnotatedType(alias, Annotation.WithBounds(bounds)) => - (alias, bounds) - case tp: HKTypeLambda => - val (alias1, bounds1) = split(tp.resType) - (tp.derivedLambdaType(resType = alias1), - HKTypeLambda.boundsFromParams(tp.typeParams, bounds1)) + def bounds(t: tpd.Tree): TypeBounds = t match + case LambdaTypeTree(_, body) => + bounds(body) + case TypeBoundsTree(lo, hi, alias) => + assert(!alias.isEmpty) + TypeBounds(lo.tpe, hi.tpe) case _ => - (tp, HKTypeLambda.boundsFromParams(tp.typeParams, TypeBounds.empty)) + TypeBounds.empty info match - case TypeAlias(tp) if isOpaqueAlias && owner.isClass => - val (alias, bounds) = split(tp) + case TypeAlias(alias) if isOpaqueAlias && owner.isClass => setAlias(alias) - bounds + HKTypeLambda.boundsFromParams(alias.typeParams, bounds(rhs)) case _ => info end opaqueToBounds diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index dde4c177b8a4..f35f72e7c237 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -588,11 +588,15 @@ class TreePickler(pickler: TastyPickler) { case LambdaTypeTree(tparams, body) => writeByte(LAMBDAtpt) withLength { pickleParams(tparams); pickleTree(body) } - case TypeBoundsTree(lo, hi) => + case TypeBoundsTree(lo, hi, alias) => writeByte(TYPEBOUNDStpt) withLength { pickleTree(lo); - if (hi ne lo) pickleTree(hi) + if alias.isEmpty then + if hi ne lo then pickleTree(hi) + else + pickleTree(hi) + pickleTree(alias) } case Hole(_, idx, args) => writeByte(HOLE) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 8d02c68d02e2..b0dd7af6bd05 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -833,11 +833,12 @@ class TreeUnpickler(reader: TastyReader, override def completerTypeParams(sym: Symbol)(implicit ctx: Context) = rhs.tpe.typeParams } - sym.info = sym.opaqueToBounds { - rhs.tpe match + sym.info = sym.opaqueToBounds( + rhs.tpe match { case _: TypeBounds | _: ClassInfo => checkNonCyclic(sym, rhs.tpe, reportErrors = false) case _ => rhs.tpe.toBounds - } + }, + rhs) if sym.isOpaqueAlias then sym.typeRef.recomputeDenot() // make sure we see the new bounds from now on sym.resetFlag(Provisional) TypeDef(rhs) @@ -1209,8 +1210,9 @@ class TreeUnpickler(reader: TastyReader, MatchTypeTree(bound, scrut, readCases(end)) case TYPEBOUNDStpt => val lo = readTpt() - val hi = if (currentAddr == end) lo else readTpt() - TypeBoundsTree(lo, hi) + val hi = if currentAddr == end then lo else readTpt() + val alias = if currentAddr == end then EmptyTree else readTpt() + TypeBoundsTree(lo, hi, alias) case HOLE => readHole(end, isType = false) case _ => diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index ef68c570f3f0..893c860fc631 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3344,20 +3344,16 @@ object Parsers { rhs match { case mtt: MatchTypeTree => bounds match { - case TypeBoundsTree(EmptyTree, upper) => + case TypeBoundsTree(EmptyTree, upper, _) => rhs = MatchTypeTree(upper, mtt.selector, mtt.cases) case _ => syntaxError(i"cannot combine lower bound and match type alias", eqOffset) } case _ => - if (mods.is(Opaque)) { - val annotType = AppliedTypeTree( - TypeTree(defn.WithBoundsAnnot.typeRef), - bounds.lo.orElse(TypeTree(defn.NothingType)) :: - bounds.hi.orElse(TypeTree(defn.AnyType)) :: Nil) - rhs = Annotated(rhs, ensureApplied(wrapNew(annotType))) - } - else syntaxError(i"cannot combine bound and alias", eqOffset) + if mods.is(Opaque) then + rhs = TypeBoundsTree(bounds.lo, bounds.hi, rhs) + else + syntaxError(i"cannot combine bound and alias", eqOffset) } makeTypeDef(rhs) } @@ -3568,7 +3564,7 @@ object Parsers { DefDef(name, tparams, vparamss, parents.head, subExpr()) else parents match - case TypeBoundsTree(_, _) :: _ => syntaxError("`=` expected") + case (_: TypeBoundsTree) :: _ => syntaxError("`=` expected") case _ => possibleTemplateStart() val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal)) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index e6937033c68c..c3232fbe086d 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -492,9 +492,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { } case ByNameTypeTree(tpt) => "=> " ~ toTextLocal(tpt) - case TypeBoundsTree(lo, hi) => - if (lo eq hi) optText(lo)(" = " ~ _) - else optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _) + case TypeBoundsTree(lo, hi, alias) => + if (lo eq hi) && alias.isEmpty then optText(lo)(" = " ~ _) + else optText(lo)(" >: " ~ _) ~ optText(hi)(" <: " ~ _) ~ optText(alias)(" = " ~ _) case Bind(name, body) => keywordText("given ").provided(tree.symbol.isOneOf(GivenOrImplicit) && !homogenizedView) ~ // Used for scala.quoted.Type in quote patterns (not pickled) changePrec(InfixPrec) { toText(name) ~ " @ " ~ toText(body) } diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 26de63087380..0ed3e18429c8 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -136,7 +136,7 @@ class ReifyQuotes extends MacroTransform { def mkTagSymbolAndAssignType(spliced: TermRef): TypeDef = { val splicedTree = tpd.ref(spliced).withSpan(expr.span) val rhs = transform(splicedTree.select(tpnme.splice)) - val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs) + val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs, EmptyTree) val local = ctx.newSymbol( owner = ctx.owner, name = UniqueName.fresh((splicedTree.symbol.name.toString + "$_").toTermName).toTypeName, diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index c8e4f8587167..e4fb2d353f90 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -997,12 +997,13 @@ class Namer { typer: Typer => } sym.info = dummyInfo2 - val rhsBodyType: TypeBounds = typedAheadType(rhs).tpe.toBounds + val rhs1 = typedAheadType(rhs) + val rhsBodyType: TypeBounds = rhs1.tpe.toBounds val unsafeInfo = if (isDerived) rhsBodyType else abstracted(rhsBodyType) if (isDerived) sym.info = unsafeInfo else { sym.info = NoCompleter - sym.info = sym.opaqueToBounds(checkNonCyclic(sym, unsafeInfo, reportErrors = true)) + sym.info = sym.opaqueToBounds(checkNonCyclic(sym, unsafeInfo, reportErrors = true), rhs1) } if sym.isOpaqueAlias then sym.typeRef.recomputeDenot() // make sure we see the new bounds from now on sym.resetFlag(Provisional) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index d0152379b4b0..794eba08f866 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -607,8 +607,11 @@ trait TypeAssigner { def assignType(tree: untpd.ByNameTypeTree, result: Tree)(implicit ctx: Context): ByNameTypeTree = tree.withType(ExprType(result.tpe)) - def assignType(tree: untpd.TypeBoundsTree, lo: Tree, hi: Tree)(implicit ctx: Context): TypeBoundsTree = - tree.withType(if (lo eq hi) TypeAlias(lo.tpe) else TypeBounds(lo.tpe, hi.tpe)) + def assignType(tree: untpd.TypeBoundsTree, lo: Tree, hi: Tree, alias: Tree)(implicit ctx: Context): TypeBoundsTree = + tree.withType( + if !alias.isEmpty then alias.tpe + else if lo eq hi then TypeAlias(lo.tpe) + else TypeBounds(lo.tpe, hi.tpe)) def assignType(tree: untpd.Bind, sym: Symbol)(implicit ctx: Context): Bind = tree.withType(NamedType(NoPrefix, sym)) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index cb770d5619f2..603b170417bf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -633,7 +633,7 @@ class Typer extends Namer tpt1 match { case AppliedTypeTree(_, targs) => - for (targ @ TypeBoundsTree(_, _) <- targs) + for case targ: TypeBoundsTree <- targs do ctx.error(WildcardOnTypeArgumentNotAllowedOnNew(), targ.sourcePos) case _ => } @@ -1445,7 +1445,7 @@ class Typer extends Namer } if (desugaredArg.isType) arg match { - case TypeBoundsTree(EmptyTree, EmptyTree) + case TypeBoundsTree(EmptyTree, EmptyTree, _) if tparam.paramInfo.isLambdaSub && tpt1.tpe.typeParamSymbols.nonEmpty && !ctx.mode.is(Mode.Pattern) => @@ -1464,7 +1464,7 @@ class Typer extends Namer args.zipWithConserve(tparams)(typedArg(_, _)).asInstanceOf[List[Tree]] } val paramBounds = tparams.lazyZip(args).map { - case (tparam, TypeBoundsTree(EmptyTree, EmptyTree)) => + case (tparam, TypeBoundsTree(EmptyTree, EmptyTree, _)) => // if type argument is a wildcard, suppress kind checking since // there is no real argument. NoType @@ -1507,14 +1507,20 @@ class Typer extends Namer } def typedTypeBoundsTree(tree: untpd.TypeBoundsTree, pt: Type)(implicit ctx: Context): Tree = { - val TypeBoundsTree(lo, hi) = tree + val TypeBoundsTree(lo, hi, alias) = tree val lo1 = typed(lo) val hi1 = typed(hi) + 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 - val tree1 = assignType(cpy.TypeBoundsTree(tree)(lo2, hi2), lo2, hi2) + if !alias1.isEmpty then + val bounds = TypeBounds(lo2.tpe, hi2.tpe) + if !bounds.contains(alias1.tpe) then + ctx.error(em"type ${alias1.tpe} outside bounds $bounds", tree.sourcePos) + + val tree1 = assignType(cpy.TypeBoundsTree(tree)(lo2, hi2, alias1), lo2, hi2, alias1) if (ctx.mode.is(Mode.Pattern)) // Associate a pattern-bound type symbol with the wildcard. // The bounds of the type symbol can be constrained when comparing a pattern type @@ -1951,13 +1957,7 @@ class Typer extends Namer val arg1 = typed(tree.arg, pt) if (ctx.mode is Mode.Type) { if arg1.isType then - val result = assignType(cpy.Annotated(tree)(arg1, annot1), arg1, annot1) - result.tpe match { - case AnnotatedType(rhs, Annotation.WithBounds(bounds)) => - if (!bounds.contains(rhs)) ctx.error(em"type $rhs outside bounds $bounds", tree.sourcePos) - case _ => - } - result + assignType(cpy.Annotated(tree)(arg1, annot1), arg1, annot1) else assert(ctx.reporter.errorsReported) TypeTree(UnspecifiedErrorType) diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index f6e1407abba0..805cb939fb95 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -253,7 +253,7 @@ Standard Section: "Comments" Comment* object TastyFormat { final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F) - val MajorVersion: Int = 19 + val MajorVersion: Int = 20 val MinorVersion: Int = 0 /** Tags used to serialize names, should update [[nameTagToString]] if a new constant is added */