From 8536c98242c3a6f35079aed22ba2e46c33bf47ca Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 3 Aug 2020 13:35:36 +0200 Subject: [PATCH] Decouple quoted Type interface from encoding Before, `quoted.Type` was defined as ```scala // old class Type[X <: AnyKind]: type T = X ``` Where `T` is the proper type of the instance of a `Type`. This is the type used for all operations within the compiler. The only purpose of the type `X` was to be able to write context bounds as `[X: Type]` and staged types `Type[X]` instead of `Type { type T = X }`. Unfortunately, the type `X` makes the assumption that `X` is known, which implies that instances of `Type` with unknown types need to be encoded with a whildcard type. A `val t: Type[?] = ...` is unusable as we cannot heal staged wildcard types, even though we do have a `t.T` which can be handled. Now, we change the definition of `Type` to only have the type member and rename it to `QuotedType`. ```scala // new class QuotedType: type T <: AnyKind ``` This solves the aforementioned limitations with unkown staged types. Now we are also able to remove the wildcard from `QuoteContext.tasty.Type.seal` and the result can be used in quotes. To keep the context bound syntax and provide more descriptive name for the concept, we defined the `quoted.Type` type alias. ```scala type Type[X <: AnyKind] = QuotedType { type T = X } ``` --- community-build/community-projects/utest | 2 +- .../dotty/tools/dotc/core/Definitions.scala | 14 +- .../dotc/core/quoted/PickledQuotes.scala | 6 +- .../dotc/transform/PCPCheckAndHeal.scala | 2 +- .../tools/dotc/transform/ReifyQuotes.scala | 6 +- .../tools/dotc/typer/QuotesAndSplices.scala | 6 +- .../scala/compiletime/package.scala | 0 .../quoted/{Type.scala => QuotedType.scala} | 18 ++- .../scala/quoted/util/ExprMap.scala | 6 +- .../scala/compiletime/package.scala | 131 ++++++++++++++++++ .../scala/quoted/Type.scala | 7 +- library/src/scala/internal/quoted/Type.scala | 8 +- library/src/scala/tasty/Reflection.scala | 8 +- staging/test-resources/repl-staging/i6263 | 2 +- tests/neg-macros/i7919.scala | 9 +- tests/pos-macros/i6693.scala | 16 +++ tests/{neg-macros => pos-macros}/i6997.scala | 2 +- tests/pos-macros/i7322/Macro_1.scala | 2 +- tests/{neg-macros => pos-macros}/i8871.scala | 2 +- tests/{neg-macros => pos-macros}/i8871b.scala | 4 +- .../quote-type-matcher/quoted_1.scala | 2 +- .../tasty-macro-positions/quoted_1.scala | 4 +- tests/run-staging/i3823-b.scala | 2 +- tests/run-staging/i3823-c.scala | 2 +- tests/run-staging/quote-nested-4.check | 6 +- tests/run-staging/quote-owners-2.scala | 2 +- 26 files changed, 218 insertions(+), 51 deletions(-) rename library/{src => src-bootstrapped}/scala/compiletime/package.scala (100%) rename library/src-bootstrapped/scala/quoted/{Type.scala => QuotedType.scala} (78%) create mode 100644 library/src-non-bootstrapped/scala/compiletime/package.scala create mode 100644 tests/pos-macros/i6693.scala rename tests/{neg-macros => pos-macros}/i6997.scala (73%) rename tests/{neg-macros => pos-macros}/i8871.scala (84%) rename tests/{neg-macros => pos-macros}/i8871b.scala (64%) diff --git a/community-build/community-projects/utest b/community-build/community-projects/utest index f9b1ebed9072..4187ea360d1e 160000 --- a/community-build/community-projects/utest +++ b/community-build/community-projects/utest @@ -1 +1 @@ -Subproject commit f9b1ebed90726d8af3e0854e3190738abcb23d71 +Subproject commit 4187ea360d1e6ddde8059d77712e2fe97f0bbe4e diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 1809a6042613..8162e12322fd 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -688,6 +688,14 @@ class Definitions { @tu lazy val QuotedExprModule_nullExpr: Symbol = QuotedExprModule.requiredMethod(nme.nullExpr) @tu lazy val QuotedExprModule_unitExpr: Symbol = QuotedExprModule.requiredMethod(nme.unitExpr) + @tu lazy val QuotedTypeAliasClass: Symbol = requiredPackage("scala.quoted").typeRef.select("Type".toTypeName).typeSymbol + + @tu lazy val QuotedTypeClass: ClassSymbol = requiredClass("scala.quoted.QuotedType") + @tu lazy val QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.spliceType) + + @tu lazy val QuotedTypeModule: Symbol = QuotedTypeClass.companionModule + @tu lazy val QuotedTypeModule_apply: Symbol = QuotedTypeModule.requiredMethod("apply") + @tu lazy val QuoteContextClass: ClassSymbol = requiredClass("scala.quoted.QuoteContext") @tu lazy val LiftableModule: Symbol = requiredModule("scala.quoted.Liftable") @@ -720,12 +728,6 @@ class Definitions { @tu lazy val InternalQuotedTypeModule: Symbol = requiredModule("scala.internal.quoted.Type") @tu lazy val InternalQuotedType_unapply: Symbol = InternalQuotedTypeModule.requiredMethod(nme.unapply) - @tu lazy val QuotedTypeClass: ClassSymbol = requiredClass("scala.quoted.Type") - @tu lazy val QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.spliceType) - - @tu lazy val QuotedTypeModule: Symbol = QuotedTypeClass.companionModule - @tu lazy val QuotedTypeModule_apply: Symbol = QuotedTypeModule.requiredMethod("apply") - @tu lazy val TastyReflectionClass: ClassSymbol = requiredClass("scala.tasty.Reflection") @tu lazy val Unpickler_unpickleExpr: Symbol = requiredMethod("scala.internal.quoted.Unpickler.unpickleExpr") diff --git a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala index 07d73a4cd03d..05e474c66b98 100644 --- a/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala +++ b/compiler/src/dotty/tools/dotc/core/quoted/PickledQuotes.scala @@ -44,7 +44,7 @@ object PickledQuotes { } /** Transform the expression into its fully spliced TypeTree */ - def quotedTypeToTree(tpe: quoted.Type[?])(using Context): Tree = { + def quotedTypeToTree(tpe: quoted.QuotedType)(using Context): Tree = { val tpe1 = tpe.asInstanceOf[scala.internal.quoted.Type[Tree]] QuoteContext.checkScopeId(tpe1.scopeId) healOwner(tpe1.typeTree) @@ -91,7 +91,7 @@ object PickledQuotes { else // Replaces type holes generated by ReifyQuotes (non-spliced types). // These are types defined in a quote and used at the same level in a nested quote. - val quotedType = splices(idx).asInstanceOf[Seq[Any] => quoted.Type[?]](reifiedArgs) + val quotedType = splices(idx).asInstanceOf[Seq[Any] => quoted.QuotedType](reifiedArgs) PickledQuotes.quotedTypeToTree(quotedType) case tree: Select => // Retain selected members @@ -134,7 +134,7 @@ object PickledQuotes { assert(tdef.symbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot)) val tree = tdef.rhs match case TypeBoundsTree(_, Hole(_, idx, args), _) => - val quotedType = splices(idx).asInstanceOf[Seq[Any] => quoted.Type[?]](args) + val quotedType = splices(idx).asInstanceOf[Seq[Any] => quoted.QuotedType](args) PickledQuotes.quotedTypeToTree(quotedType) case TypeBoundsTree(_, tpt, _) => tpt diff --git a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala index 7f9b1fcbed2b..9fbb239d9c27 100644 --- a/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala +++ b/compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala @@ -222,7 +222,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages( * Emits and error if `T` cannot be healed and returns `T`. */ protected def tryHeal(sym: Symbol, tp: TypeRef, pos: SourcePosition)(using Context): TypeRef = { - val reqType = defn.QuotedTypeClass.typeRef.appliedTo(tp) + val reqType = defn.QuotedTypeAliasClass.typeRef.appliedTo(tp) val tag = ctx.typer.inferImplicitArg(reqType, pos.span) tag.tpe match diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 1518492e6b1d..48fd275b89f7 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -265,7 +265,7 @@ class ReifyQuotes extends MacroTransform { } assert(tpw.isInstanceOf[ValueType]) val argTpe = - if (tree.isType) defn.QuotedTypeClass.typeRef.appliedTo(tpw) + if (tree.isType) defn.QuotedTypeAliasClass.typeRef.appliedTo(tpw) else defn.FunctionType(1, isContextual = true).appliedTo(defn.QuoteContextClass.typeRef, defn.QuotedExprClass.typeRef.appliedTo(tpw)) val selectArg = arg.select(nme.apply).appliedTo(Literal(Constant(i))).cast(argTpe) val capturedArg = SyntheticValDef(UniqueName.fresh(tree.symbol.name.toTermName).toTermName, selectArg) @@ -335,7 +335,9 @@ class ReifyQuotes extends MacroTransform { def getTypeHoleType(using Context) = new TypeMap() { override def apply(tp: Type): Type = tp match case tp: TypeRef if tp.typeSymbol.isTypeSplice => - apply(tp.dealias) + val dealiased = tp.dealias + if tp == dealiased then apply(tp.symbol.info.hiBound) + else apply(tp.dealias) case tp @ TypeRef(pre, _) if pre == NoPrefix || pre.termSymbol.isLocal => val hiBound = tp.typeSymbol.info match case info @ ClassInfo(_, _, classParents, _, _) => classParents.reduce(_ & _) diff --git a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala index 4156f8835125..e75c936db2b9 100644 --- a/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala +++ b/compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala @@ -167,7 +167,7 @@ trait QuotesAndSplices { case _ => TypeBounds.empty val typeSym = newSymbol(spliceOwner(ctx), name, EmptyFlags, typeSymInfo, NoSymbol, tree.expr.span) typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuotedMatcher_patternTypeAnnot.typeRef)).withSpan(tree.expr.span))) - val pat = typedPattern(tree.expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))( + val pat = typedPattern(tree.expr, defn.QuotedTypeAliasClass.typeRef.appliedTo(typeSym.typeRef))( using spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx))) pat.select(tpnme.spliceType) else @@ -298,7 +298,7 @@ trait QuotesAndSplices { if (variance == -1) tdef.symbol.addAnnotation(Annotation(New(ref(defn.InternalQuotedMatcher_fromAboveAnnot.typeRef)).withSpan(tdef.span))) val bindingType = getBinding(tdef.symbol).symbol.typeRef - val bindingTypeTpe = AppliedType(defn.QuotedTypeClass.typeRef, bindingType :: Nil) + val bindingTypeTpe = AppliedType(defn.QuotedTypeAliasClass.typeRef, bindingType :: Nil) val bindName = tdef.name.toString.stripPrefix("$").toTermName val sym = newPatternBoundSymbol(bindName, bindingTypeTpe, tdef.span, flags = ImplicitTerm)(using ctx0) buff += Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingTypeTpe)).withSpan(tdef.span) @@ -436,7 +436,7 @@ trait QuotesAndSplices { else typed(untpd.Tuple(splices.map(x => untpd.TypedSplice(replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType) val unapplySym = if (tree.quoted.isTerm) defn.InternalQuotedExpr_unapply else defn.InternalQuotedType_unapply - val quoteClass = if (tree.quoted.isTerm) defn.QuotedExprClass else defn.QuotedTypeClass + val quoteClass = if (tree.quoted.isTerm) defn.QuotedExprClass else defn.QuotedTypeAliasClass val quotedPattern = if (tree.quoted.isTerm) ref(defn.InternalQuoted_exprQuote.termRef).appliedToType(defn.AnyType).appliedTo(shape).select(nme.apply).appliedTo(qctx) else ref(defn.QuotedTypeModule_apply.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx) diff --git a/library/src/scala/compiletime/package.scala b/library/src-bootstrapped/scala/compiletime/package.scala similarity index 100% rename from library/src/scala/compiletime/package.scala rename to library/src-bootstrapped/scala/compiletime/package.scala diff --git a/library/src-bootstrapped/scala/quoted/Type.scala b/library/src-bootstrapped/scala/quoted/QuotedType.scala similarity index 78% rename from library/src-bootstrapped/scala/quoted/Type.scala rename to library/src-bootstrapped/scala/quoted/QuotedType.scala index b0ad55fda478..9ed799a136eb 100644 --- a/library/src-bootstrapped/scala/quoted/Type.scala +++ b/library/src-bootstrapped/scala/quoted/QuotedType.scala @@ -3,9 +3,12 @@ package scala.quoted import scala.annotation.compileTimeOnly import scala.quoted.show.SyntaxHighlight -/** Quoted type (or kind) `T` */ -abstract class Type[X <: AnyKind] private[scala] { - type T = X +/** Quoted type (or kind) `X` */ +type Type[X <: AnyKind] = QuotedType { type T = X } + +/** A TypeTree with a known type (or kind) `T` */ +abstract class QuotedType private[scala] { + type T <: AnyKind /** Show a source code like representation of this type without syntax highlight */ def show(using qctx: QuoteContext): String = @@ -21,12 +24,17 @@ abstract class Type[X <: AnyKind] private[scala] { } /** Some basic type tags, currently incomplete */ -object Type { +object QuotedType { /** Return a quoted.Type with the given type */ - @compileTimeOnly("Reference to `scala.quoted.Type.apply` was not handled by ReifyQuotes") + @compileTimeOnly("Reference to `scala.quoted.QuotedType.apply` was not handled by ReifyQuotes") given apply[T <: AnyKind] as (QuoteContext ?=> Type[T]) = ??? + + // TODO: Move Tags + // these are here for a compiler optimization not for the user. users should write '[Int] directly + // they should be in sclaa.internal.quoted.Type + def UnitTag: QuoteContext ?=> Type[Unit] = qctx.tasty.defn.UnitType.seal.asInstanceOf[quoted.Type[Unit]] diff --git a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala index bc2237c344b2..f53d6eb39a64 100644 --- a/library/src-bootstrapped/scala/quoted/util/ExprMap.scala +++ b/library/src-bootstrapped/scala/quoted/util/ExprMap.scala @@ -65,10 +65,8 @@ trait ExprMap { // TODO improve code case AppliedType(TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), ""), List(tp0: Type)) => // TODO rewrite without using quotes - type T - val qtp: quoted.Type[T] = tp0.seal.asInstanceOf[quoted.Type[T]] - given qtp.type = qtp - '[Seq[T]].unseal.tpe + val t = tp0.seal.asInstanceOf[quoted.QuotedType { type T <: Any }] + '[Seq[$t]].unseal.tpe case tp => tp Typed.copy(tree)(transformTerm(expr, tp), transformTypeTree(tpt)) case tree: NamedArg => diff --git a/library/src-non-bootstrapped/scala/compiletime/package.scala b/library/src-non-bootstrapped/scala/compiletime/package.scala new file mode 100644 index 000000000000..821cee2841c3 --- /dev/null +++ b/library/src-non-bootstrapped/scala/compiletime/package.scala @@ -0,0 +1,131 @@ +package scala + +import scala.quoted._ + +package object compiletime { + + /** Use this method when you have a type, do not have a value for it but want to + * pattern match on it. For example, given a type `Tup <: Tuple`, one can + * pattern-match on it as follows: + * ``` + * erasedValue[Tup] match { + * case _: EmptyTuple => ... + * case _: h *: t => ... + * } + * ``` + */ + erased def erasedValue[T]: T = ??? + + /** The error method is used to produce user-defined compile errors during inline expansion. + * If an inline expansion results in a call error(msgStr) the compiler produces an error message containing the given msgStr. + * + * ```scala + * error("My error message") + * ``` + * or + * ```scala + * error(code"My error of this code: ${println("foo")}") + * ``` + */ + inline def error(inline msg: String): Nothing = ??? + + extension (inline self: StringContext): + /** Returns the string representation of interpolated elaborated code: + * + * ```scala + * inline def logged(p1: => Any) = { + * val c = code"code: $p1" + * val res = p1 + * (c, p1) + * } + * logged(identity("foo")) + * // above is equivalent to: + * // ("code: scala.Predef.identity("foo")", identity("foo")) + * ``` + * + * @note only by-name arguments will be displayed as "code". + * Other values may display unintutively. + */ + transparent inline def code (inline args: Any*): String = + throw new Error("Non-bootstrapped lib") + end extension + + /** Same as `constValue` but returns a `None` if a constant value + * cannot be constructed from the provided type. Otherwise returns + * that value wrapped in `Some`. + */ + inline def constValueOpt[T]: Option[T] = ??? + + /** Given a constant, singleton type `T`, convert it to a value + * of the same singleton type. For example: `assert(constValue[1] == 1)`. + */ + inline def constValue[T]: T = ??? + + /** Given a tuple type `(X1, ..., Xn)`, returns a tuple value + * `(constValue[X1], ..., constValue[Xn])`. + */ + inline def constValueTuple[T <: Tuple]: Tuple.Widen[T]= + val res = + inline erasedValue[T] match + case _: EmptyTuple => EmptyTuple + case _: (t *: ts) => constValue[t] *: constValueTuple[ts] + end match + res.asInstanceOf[Tuple.Widen[T]] + end constValueTuple + + /** Summons first given matching one of the listed cases. E.g. in + * + * given B { ... } + * + * summonFrom { + * case given A => 1 + * case given B => 2 + * case given C => 3 + * case _ => 4 + * } + * + * the returned value would be `2`. + */ + transparent inline def summonFrom[T](f: Nothing => T): T = ??? + + + /** Summon a given value of type `T`. Usually, the argument is not passed explicitly. + * The summoning is delayed until the call has been fully inlined. + * + * @tparam T the type of the value to be summoned + * @return the given value typed as the provided type parameter + */ + transparent inline def summonInline[T]: T = summonFrom { + case t: T => t + } + + /** Given a tuple T, summons each of its member types and returns them in + * a Tuple. + * + * @tparam T the tuple containing the types of the values to be summoned + * @return the given values typed as elements of the tuple + */ + inline def summonAll[T <: Tuple]: Tuple.Widen[T] = + val res = + inline erasedValue[T] match + case _: EmptyTuple => EmptyTuple + case _: (t *: ts) => summonInline[t] *: summonAll[ts] + end match + res.asInstanceOf[Tuple.Widen[T]] + end summonAll + + /** Succesor of a natural number where zero is the type 0 and successors are reduced as if the definition was + * + * type S[N <: Int] <: Int = N match { + * case 0 => 1 + * case 1 => 2 + * case 2 => 3 + * ... + * case 2147483646 => 2147483647 + * } + */ + type S[N <: Int] <: Int + + /** Assertion that an argument is by-name. Used for nullability checking. */ + def byName[T](x: => T): T = x +} diff --git a/library/src-non-bootstrapped/scala/quoted/Type.scala b/library/src-non-bootstrapped/scala/quoted/Type.scala index 01f8e917fa06..12dd579b0b62 100644 --- a/library/src-non-bootstrapped/scala/quoted/Type.scala +++ b/library/src-non-bootstrapped/scala/quoted/Type.scala @@ -1,5 +1,8 @@ package scala.quoted -abstract class Type[T <: AnyKind] private[scala]: - type `$splice` = T +abstract class QuotedType private[scala]: + type `$splice` + type T <: AnyKind def unseal(using qctx: QuoteContext): qctx.tasty.TypeTree + +type Type[X <: AnyKind] = QuotedType { type T = X } diff --git a/library/src/scala/internal/quoted/Type.scala b/library/src/scala/internal/quoted/Type.scala index b5949c9cae60..4871d7e18c07 100644 --- a/library/src/scala/internal/quoted/Type.scala +++ b/library/src/scala/internal/quoted/Type.scala @@ -3,7 +3,7 @@ package scala.internal.quoted import scala.quoted._ /** Quoted type (or kind) `T` backed by a tree */ -final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quoted.Type[Any] { +final class Type[Tree](val typeTree: Tree, val scopeId: Int) extends scala.quoted.QuotedType { override def equals(that: Any): Boolean = that match { case that: Type[_] => typeTree == // TastyTreeExpr are wrappers around trees, therfore they are equals if their trees are equal. @@ -31,13 +31,13 @@ object Type { * - scala.internal.Quoted.patternHole[T]: hole that matches an expression `x` of type `Type[U]` * if `U <:< T` and returns `x` as part of the match. * - * @param scrutineeType `Type[_]` on which we are pattern matching - * @param patternType `Type[_]` containing the pattern tree + * @param scrutineeType `QuotedType` on which we are pattern matching + * @param patternType `QuotedType` containing the pattern tree * @param hasTypeSplices `Boolean` notify if the pattern has type splices (if so we use a GADT context) * @param qctx the current QuoteContext * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Type[Ti]`` */ - def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeType: scala.quoted.Type[_])(using patternType: scala.quoted.Type[_], + def unapply[TypeBindings <: Tuple, Tup <: Tuple](scrutineeType: scala.quoted.QuotedType)(using patternType: scala.quoted.QuotedType, hasTypeSplices: Boolean, qctx: QuoteContext): Option[Tup] = { new Matcher.QuoteMatcher[qctx.type].typeTreeMatch(scrutineeType.unseal, patternType.unseal, hasTypeSplices).asInstanceOf[Option[Tup]] } diff --git a/library/src/scala/tasty/Reflection.scala b/library/src/scala/tasty/Reflection.scala index 8d70981ec7ad..673e1e07efd4 100644 --- a/library/src/scala/tasty/Reflection.scala +++ b/library/src/scala/tasty/Reflection.scala @@ -1753,7 +1753,7 @@ class Reflection(private[scala] val internal: CompilerInterface) { self => /** Returns the type (Type) of T */ def typeOf[T](using qtype: scala.quoted.Type[T], ctx: Context): Type = - qtype.asInstanceOf[scala.internal.quoted.Type[T]].typeTree.asInstanceOf[TypeTree].tpe + qtype.asInstanceOf[scala.internal.quoted.Type[TypeTree]].typeTree.tpe given TypeOrBoundsOps as AnyRef: /** Members of `TypeOrBounds` */ @@ -1783,9 +1783,9 @@ class Reflection(private[scala] val internal: CompilerInterface) { self => extension (self: Type): - /** Convert `Type` to an `quoted.Type[_]` */ - def seal(using ctx: Context): scala.quoted.Type[_] = - new scala.internal.quoted.Type(Inferred(self), internal.compilerId) + /** Wraps the `Type` in a `TypeTree` and convert it to a `quoted.QuotedType` */ + def seal(using ctx: Context): scala.quoted.QuotedType = + new scala.internal.quoted.Type(Inferred(self), internal.compilerId).asInstanceOf[scala.quoted.QuotedType] /** Is `self` type the same as `that` type? * This is the case iff `self <:< that` and `that <:< self`. diff --git a/staging/test-resources/repl-staging/i6263 b/staging/test-resources/repl-staging/i6263 index 2dd3e41cc695..17f8a62a5511 100644 --- a/staging/test-resources/repl-staging/i6263 +++ b/staging/test-resources/repl-staging/i6263 @@ -3,7 +3,7 @@ scala> import quoted.staging._ scala> implicit def toolbox: Toolbox = Toolbox.make(getClass.getClassLoader) def toolbox: quoted.staging.Toolbox scala> def fn[T : Type](v : T) = println("ok") -def fn[T](v: T)(implicit evidence$1: quoted.Type[T]): Unit +def fn[T](v: T)(implicit evidence$1: scala.quoted.Type[T]): Unit scala> withQuoteContext { fn("foo") } ok scala> withQuoteContext { fn((1,2)) } diff --git a/tests/neg-macros/i7919.scala b/tests/neg-macros/i7919.scala index dff211eb562d..d98258f30b7d 100644 --- a/tests/neg-macros/i7919.scala +++ b/tests/neg-macros/i7919.scala @@ -4,7 +4,8 @@ object Test { def staged[T](using qctx: QuoteContext) = { import qctx.tasty._ given typeT as quoted.Type[T] // error - val tTypeTree = typeT.unseal + val typeT2: quoted.Type[Int] = ??? + val tTypeTree = typeT2.unseal val tt = typeOf[T] '{ "in staged" } } @@ -13,8 +14,12 @@ object Test { new Expr[Int] // error class Expr2 extends Expr[Int] // error + given Type // error + new Type // error + class Type2 extends Type // error + given Type[Int] // error new Type[Int] // error - class Type2 extends Type[Int] // error + class Type3 extends Type[Int] // error } diff --git a/tests/pos-macros/i6693.scala b/tests/pos-macros/i6693.scala new file mode 100644 index 000000000000..7d57950f5ef8 --- /dev/null +++ b/tests/pos-macros/i6693.scala @@ -0,0 +1,16 @@ +package towers.computes + +import quoted._ + +sealed abstract class Computes[T] + +object Computes { + + opaque type Opaque[T] = Int + + implicit class ComputesApplication1[T : Type](fn : Computes[Opaque[T]]) { + def apply[A](arg1 : Computes[A]) : Computes[T] = ??? + } + + def let[V, T : Type](value : Computes[V], body : Computes[Opaque[T]]) : Computes[T] = body(value) +} diff --git a/tests/neg-macros/i6997.scala b/tests/pos-macros/i6997.scala similarity index 73% rename from tests/neg-macros/i6997.scala rename to tests/pos-macros/i6997.scala index c90239ef986a..fb8f8e6d1aa4 100644 --- a/tests/neg-macros/i6997.scala +++ b/tests/pos-macros/i6997.scala @@ -2,7 +2,7 @@ import scala.quoted._ class Foo { def mcrImpl(body: Expr[Any])(using t: Type[_ <: Any])(using ctx: QuoteContext): Expr[Any] = '{ - val tmp = ???.asInstanceOf[$t] // error // error + val tmp = ???.asInstanceOf[$t] tmp } } diff --git a/tests/pos-macros/i7322/Macro_1.scala b/tests/pos-macros/i7322/Macro_1.scala index 296733ab36cf..d465d28ee099 100644 --- a/tests/pos-macros/i7322/Macro_1.scala +++ b/tests/pos-macros/i7322/Macro_1.scala @@ -4,4 +4,4 @@ trait M[T] { def f: Any } -inline def g[T: Type](em: Expr[M[T]])(using QuoteContext) = '{$em.f} \ No newline at end of file +inline def g[T: Type](em: Expr[M[T]])(using QuoteContext) = '{$em.f} diff --git a/tests/neg-macros/i8871.scala b/tests/pos-macros/i8871.scala similarity index 84% rename from tests/neg-macros/i8871.scala rename to tests/pos-macros/i8871.scala index 4fa1bd3af936..37eda3ea6a22 100644 --- a/tests/neg-macros/i8871.scala +++ b/tests/pos-macros/i8871.scala @@ -3,6 +3,6 @@ object Macro { def impl[A : Type](using qctx: QuoteContext): Unit = { import qctx.tasty._ val tpe = typeOf[A].seal.asInstanceOf[quoted.Type[_ <: AnyRef]] - '{ (a: ${tpe}) => ???} // error + '{ (a: ${tpe}) => ???} } } diff --git a/tests/neg-macros/i8871b.scala b/tests/pos-macros/i8871b.scala similarity index 64% rename from tests/neg-macros/i8871b.scala rename to tests/pos-macros/i8871b.scala index bb363e90f29e..a3ba33793ca2 100644 --- a/tests/neg-macros/i8871b.scala +++ b/tests/pos-macros/i8871b.scala @@ -2,8 +2,8 @@ import scala.quoted._ object Macro { def impl[A : Type](using qctx: QuoteContext): Unit = { import qctx.tasty._ - val tpe/*: quoted.Type[? <: AnyKind]*/ = typeOf[A].seal - '{ f[$tpe] } // error + val tpe/*: quoted.QuotedType */ = typeOf[A].seal + '{ f[$tpe] } } def f[T <: AnyKind]: Unit = () } diff --git a/tests/run-macros/quote-type-matcher/quoted_1.scala b/tests/run-macros/quote-type-matcher/quoted_1.scala index 3867d331e7db..078ac5975309 100644 --- a/tests/run-macros/quote-type-matcher/quoted_1.scala +++ b/tests/run-macros/quote-type-matcher/quoted_1.scala @@ -9,7 +9,7 @@ object Macros { val res = scala.internal.quoted.Type.unapply[Tuple, Tuple](a)(using b, true, qctx).map { tup => tup.toArray.toList.map { - case r: quoted.Type[_] => + case r: quoted.QuotedType => s"Type(${r.unseal.show})" case r: String => s"String($r)" diff --git a/tests/run-macros/tasty-macro-positions/quoted_1.scala b/tests/run-macros/tasty-macro-positions/quoted_1.scala index bc94ec971729..b1afd19b22ce 100644 --- a/tests/run-macros/tasty-macro-positions/quoted_1.scala +++ b/tests/run-macros/tasty-macro-positions/quoted_1.scala @@ -8,7 +8,7 @@ object Macros { inline def fun3[T]: Unit = ${ impl2('[T]) } - def impl(x: Expr[Any])(using qctx: QuoteContext) : Expr[Unit] = { + def impl(x: Expr[Any])(using qctx: QuoteContext): Expr[Unit] = { import qctx.tasty._ val pos = x.unseal.underlyingArgument.pos val code = x.unseal.underlyingArgument.show @@ -18,7 +18,7 @@ object Macros { } } - def impl2[T](x: quoted.Type[T])(using qctx: QuoteContext) : Expr[Unit] = { + def impl2[T](x: Type[T])(using qctx: QuoteContext): Expr[Unit] = { import qctx.tasty._ val pos = x.unseal.pos val code = x.unseal.show diff --git a/tests/run-staging/i3823-b.scala b/tests/run-staging/i3823-b.scala index f4f77d3cabf5..151bfc4a96ae 100644 --- a/tests/run-staging/i3823-b.scala +++ b/tests/run-staging/i3823-b.scala @@ -6,6 +6,6 @@ object Test { def f[T](x: Expr[T])(implicit t: Type[T]) = '{ val z: $t = $x } - println(f('{2})(Type.IntTag).show) + println(f('{2})(QuotedType.IntTag).show) } } diff --git a/tests/run-staging/i3823-c.scala b/tests/run-staging/i3823-c.scala index 5a6074788840..9156957cb42f 100644 --- a/tests/run-staging/i3823-c.scala +++ b/tests/run-staging/i3823-c.scala @@ -6,6 +6,6 @@ object Test { def f[T](x: Expr[T])(implicit t: Type[T]) = '{ val z = $x } - println(f('{2})(Type.IntTag).show) + println(f('{2})(QuotedType.IntTag).show) } } diff --git a/tests/run-staging/quote-nested-4.check b/tests/run-staging/quote-nested-4.check index ca8eaa483f2f..800bf1e34cad 100644 --- a/tests/run-staging/quote-nested-4.check +++ b/tests/run-staging/quote-nested-4.check @@ -1,5 +1,7 @@ ((qctx: scala.quoted.QuoteContext) ?=> { - val t: scala.quoted.Type[scala.Predef.String] = scala.quoted.Type.apply[scala.Predef.String].apply(using qctx) + val t: scala.quoted.QuotedType$package.Type[scala.Predef.String] = scala.quoted.QuotedType.apply[scala.Predef.String].apply(using qctx) - (t: scala.quoted.Type[scala.Predef.String]) + (t: scala.quoted.QuotedType { + type T >: scala.Predef.String <: scala.Predef.String + }) }) diff --git a/tests/run-staging/quote-owners-2.scala b/tests/run-staging/quote-owners-2.scala index 6bb0935ee1d3..f36cd45af5f2 100644 --- a/tests/run-staging/quote-owners-2.scala +++ b/tests/run-staging/quote-owners-2.scala @@ -5,7 +5,7 @@ import scala.quoted.staging._ object Test { given Toolbox = Toolbox.make(getClass.getClassLoader) def main(args: Array[String]): Unit = run { - val q = f(g(Type.IntTag)) + val q = f(g(QuotedType.IntTag)) println(q.show) '{ println($q) } }