Skip to content

Rename Type.T to Type.Underlying #10097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ class Definitions {
@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 QuotedType_splice: Symbol = QuotedTypeClass.requiredType(tpnme.Underlying)

@tu lazy val QuotedTypeModule: Symbol = QuotedTypeClass.companionModule
@tu lazy val QuotedTypeModule_apply: Symbol = QuotedTypeModule.requiredMethod("apply")
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ object StdNames {
final val Tree: N = "Tree"
final val Type : N = "Type"
final val TypeTree: N = "TypeTree"
final val Underlying: N = "Underlying"

// Annotation simple names, used in Namer
final val BeanPropertyAnnot: N = "BeanProperty"
Expand Down Expand Up @@ -583,7 +584,6 @@ object StdNames {
val setSymbol: N = "setSymbol"
val setType: N = "setType"
val setTypeSignature: N = "setTypeSignature"
val spliceType: N = "T"
val standardInterpolator: N = "standardInterpolator"
val staticClass : N = "staticClass"
val staticModule : N = "staticModule"
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,13 @@ object PCPCheckAndHeal {

private def mkTagSymbolAndAssignType(spliced: TermRef): TypeDef = {
val splicedTree = tpd.ref(spliced).withSpan(span)
val rhs = splicedTree.select(tpnme.spliceType).withSpan(span)
val rhs = splicedTree.select(tpnme.Underlying).withSpan(span)
val alias = ctx.typeAssigner.assignType(untpd.TypeBoundsTree(rhs, rhs), rhs, rhs, EmptyTree)
val local = newSymbol(
owner = ctx.owner,
name = UniqueName.fresh((splicedTree.symbol.name.toString + "$_").toTermName).toTypeName,
flags = Synthetic,
info = TypeAlias(splicedTree.tpe.select(tpnme.spliceType)),
info = TypeAlias(splicedTree.tpe.select(tpnme.Underlying)),
coord = span).asType
local.addAnnotation(Annotation(defn.InternalQuoted_QuoteTypeTagAnnot))
ctx.typeAssigner.assignType(untpd.TypeDef(local.name, alias), local)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ class ReifyQuotes extends MacroTransform {
case tree: RefTree if isCaptured(tree.symbol, level) =>
val body = capturers(tree.symbol).apply(tree)
if (tree.isType)
transformSpliceType(body, body.select(tpnme.spliceType))
transformSpliceType(body, body.select(tpnme.Underlying))
else
val splice = ref(defn.InternalQuoted_exprSplice).appliedToType(tree.tpe).appliedTo(body)
transformSplice(body, splice)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -176,9 +176,9 @@ trait QuotesAndSplices {
typeSym.addAnnotation(Annotation(New(ref(defn.InternalQuotedPatterns_patternTypeAnnot.typeRef)).withSpan(tree.expr.span)))
val pat = typedPattern(expr, defn.QuotedTypeClass.typeRef.appliedTo(typeSym.typeRef))(
using spliceContext.retractMode(Mode.QuotedPattern).withOwner(spliceOwner(ctx)))
pat.select(tpnme.spliceType)
pat.select(tpnme.Underlying)
else
val tree1 = typedSelect(untpd.Select(tree.expr, tpnme.spliceType), pt)(using spliceContext).withSpan(tree.span)
val tree1 = typedSelect(untpd.Select(tree.expr, tpnme.Underlying), pt)(using spliceContext).withSpan(tree.span)
val msg = em"Consider using canonical type reference ${tree1.tpe} instead"
if sourceVersion.isAtLeast(`3.1-migration`) then report.error(msg, tree.srcPos)
else report.warning(msg, tree.srcPos)
Expand Down
27 changes: 13 additions & 14 deletions docs/docs/reference/metaprogramming/macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,25 +187,25 @@ Indeed, the definition of `to` above uses `T` in the next stage, there is a
quote but no splice between the parameter binding of `T` and its
usage. But the code can be rewritten by adding a binding of a `Type[T]` tag:
```scala
def to[T, R: Type](f: Expr[T] => Expr[R])(using t: Type[T])(using QuoteContext): Expr[T => R] =
'{ (x: $t) => ${ f('x) } }
def to[T, R](f: Expr[T] => Expr[R])(using Type[T], Type[R], QuoteContext): Expr[T => R] =
'{ (x: T) => ${ f('x) } }
```
In this version of `to`, the type of `x` is now the result of
splicing the `Type` value `t`. This operation _is_ splice correct -- there
is one quote and one splice between the use of `t` and its definition.

To avoid clutter, the Scala implementation tries to convert any type
reference to a type `T` in subsequent phases to a type-splice, by rewriting `T` to `${ summon[Type[T]] }`.
reference to a type `T` in subsequent phases to a type-splice, by rewriting `T` to `summon[Type[T]].Underlying`.
For instance, the user-level definition of `to`:

```scala
def to[T: Type, R: Type](f: Expr[T] => Expr[R])(using QuoteContext): Expr[T => R] =
def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T], r: Type[R], QuoteContext): Expr[T => R] =
'{ (x: T) => ${ f('x) } }
```
would be rewritten to
```scala
def to[T: Type, R: Type](f: Expr[T] => Expr[R])(using QuoteContext): Expr[T => R] =
'{ (x: ${ summon[Type[T]] }) => ${ f('x) } }
def to[T, R](f: Expr[T] => Expr[R])(using t: Type[T], r: Type[R], QuoteContext): Expr[T => R] =
'{ (x: t.Underlying }) => ${ f('x) } }
```
The `summon` query succeeds because there is a given instance of
type `Type[T]` available (namely the given parameter corresponding
Expand Down Expand Up @@ -499,10 +499,10 @@ function `f` and one `sum` that performs a sum by delegating to `map`.

```scala
object Macros {
def map[T](arr: Expr[Array[T]], f: Expr[T] => Expr[Unit])(using t: Type[T], qctx: QuoteContext): Expr[Unit] = '{
def map[T](arr: Expr[Array[T]], f: Expr[T] => Expr[Unit])(using Type[T], QuoteContext): Expr[Unit] = '{
var i: Int = 0
while (i < ($arr).length) {
val element: $t = ($arr)(i)
val element: T = ($arr)(i)
${f('element)}
i += 1
}
Expand Down Expand Up @@ -703,11 +703,11 @@ Sometimes it is necessary to get a more precise type for an expression. This can
```scala
def f(exp: Expr[Any])(using QuoteContext) =
expr match
case '{ $x: $t } =>
case '{ $x: $T } =>
// If the pattern match succeeds, then there is some type `T` such that
// - `x` is bound to a variable of type `Expr[T]`
// - `t` is bound to a given instance of type `Type[T]`
// That is, we have `x: Expr[T]` and `given t: Type[T]`, for some (unknown) type `T`.
// - `T` is bound to a new type T and a given instance `Type[T]` is provided for it
// That is, we have `x: Expr[T]` and `given Type[T]`, for some (unknown) type `T`.
```

This might be used to then perform an implicit search as in:
Expand All @@ -720,9 +720,8 @@ private def showMeExpr(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using
argsExpr match {
case Varargs(argExprs) =>
val argShowedExprs = argExprs.map {
case '{ $arg: $tp } =>
val showTp = '[Show[$tp]]
Expr.summon(using showTp) match {
case '{ $arg: $T } =>
Expr.summon[Show[T]] match {
case Some(showExpr) => '{ $showExpr.show($arg) }
case None => Reporting.error(s"could not find implicit for ${showTp.show}", arg); '{???}
}
Expand Down
6 changes: 4 additions & 2 deletions library/src-bootstrapped/scala/quoted/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import scala.annotation.compileTimeOnly
import scala.quoted.show.SyntaxHighlight

/** Quoted type (or kind) `T` */
abstract class Type[X <: AnyKind] private[scala] {
type T = X
abstract class Type[T <: AnyKind] private[scala] {

/** The type represented `Type` */
type Underlying = T

/** Show a source code like representation of this type without syntax highlight */
def show(using qctx: QuoteContext): String =
Expand Down
5 changes: 3 additions & 2 deletions library/src-non-bootstrapped/scala/quoted/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package scala.quoted

import scala.annotation.compileTimeOnly

abstract class Type[X <: AnyKind] private[scala]:
type T = X
abstract class Type[T <: AnyKind] private[scala]:
type Underlying = T

def unseal(using qctx: QuoteContext): qctx.reflect.TypeTree

object Type:
Expand Down
2 changes: 1 addition & 1 deletion tests/pos-macros/i9518/Macro_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def shiftTerm(using QuoteContext): Expr[Unit] = {
val tp1 = '[CB[Int]].unseal.tpe
val tp2 = '[([X] =>> CB[X])[Int]].unseal.tpe
val ta = '[[X] =>> CB[X]]
val tp3 = '[ta.T[Int]].unseal.tpe
val tp3 = '[ta.Underlying[Int]].unseal.tpe
val tp4 = '[CB].unseal.tpe.appliedTo(TypeRepr.of[Int])
assert(nTree.tpe <:< tp1)
assert(nTree.tpe <:< tp2)
Expand Down