Skip to content

Remove quoted.Type synthesization #9448

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 8 commits into from
Jul 29, 2020
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/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ class Compiler {
protected def frontendPhases: List[List[Phase]] =
List(new FrontEnd) :: // Compiler frontend: scanner, parser, namer, typer
List(new YCheckPositions) :: // YCheck positions
List(new Staging) :: // Check PCP, heal quoted types and expand macros
List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks
List(new semanticdb.ExtractSemanticDB) :: // Extract info into .semanticdb files
List(new PostTyper) :: // Additional checks and cleanups after type checking
List(new Staging) :: // Check PCP, heal quoted types and expand macros
List(new sbt.ExtractAPI) :: // Sends a representation of the API of classes to sbt via callbacks
List(new SetRootTree) :: // Set the `rootTreeOrProvider` on class symbols
Nil
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case New(_) | Closure(_, _, _) =>
Pure
case TypeApply(fn, _) =>
if (fn.symbol.is(Erased) || fn.symbol == defn.InternalQuoted_typeQuote || fn.symbol == defn.Predef_classOf) Pure else exprPurity(fn)
if (fn.symbol.is(Erased) || fn.symbol == defn.QuotedTypeModule_apply || fn.symbol == defn.Predef_classOf) Pure else exprPurity(fn)
case Apply(fn, args) =>
def isKnownPureOp(sym: Symbol) =
sym.owner.isPrimitiveValueClass
Expand Down
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 @@ -693,7 +693,6 @@ class Definitions {
@tu lazy val InternalQuoted_exprQuote : Symbol = InternalQuotedModule.requiredMethod("exprQuote")
@tu lazy val InternalQuoted_exprSplice : Symbol = InternalQuotedModule.requiredMethod("exprSplice")
@tu lazy val InternalQuoted_exprNestedSplice : Symbol = InternalQuotedModule.requiredMethod("exprNestedSplice")
@tu lazy val InternalQuoted_typeQuote : Symbol = InternalQuotedModule.requiredMethod("typeQuote")
@tu lazy val InternalQuoted_QuoteTypeTagAnnot: ClassSymbol = InternalQuotedModule.requiredClass("quoteTypeTag")

@tu lazy val InternalQuotedMatcher: Symbol = requiredModule("scala.internal.quoted.Matcher")
Expand All @@ -713,6 +712,7 @@ class Definitions {
@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")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,5 @@ class DecompilerPrinter(_ctx: Context) extends RefinedPrinter(_ctx) {

override protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text =
if (tree.symbol eq defn.InternalQuoted_exprQuote) "'"
else if (tree.symbol eq defn.InternalQuoted_typeQuote) "'[" ~ toTextGlobal(tree.args, ", ") ~ "]"
else super.typeApplyText(tree)
}
11 changes: 4 additions & 7 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
("{" ~ toText(trees, "\n") ~ "}").close

protected def typeApplyText[T >: Untyped](tree: TypeApply[T]): Text = {
val isQuote = !printDebug && tree.fun.hasType && tree.fun.symbol == defn.InternalQuoted_typeQuote
val (open, close) = if (isQuote) (keywordStr("'["), keywordStr("]")) else ("[", "]")
val funText = toTextLocal(tree.fun).provided(!isQuote)
val funText = toTextLocal(tree.fun)
tree.fun match {
case Select(New(tpt), nme.CONSTRUCTOR) if tpt.typeOpt.dealias.isInstanceOf[AppliedType] =>
funText // type was already printed by toText(new)
case _ =>
funText ~ open ~ toTextGlobal(tree.args, ", ") ~ close
funText ~ "[" ~ toTextGlobal(tree.args, ", ") ~ "]"
}
}

Expand Down Expand Up @@ -632,9 +630,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
case Number(digits, kind) =>
digits
case Quote(tree) =>
if (tree.isType) keywordStr("'[") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("]")
else keywordStr("'{") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
case Quote(tree) if tree.isTerm =>
keywordStr("'{") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
case Splice(tree) =>
keywordStr("${") ~ toTextGlobal(dropBlock(tree)) ~ keywordStr("}")
case TypSplice(tree) =>
Expand Down
6 changes: 4 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,10 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
tp match
case tp: TypeRef =>
tp.prefix match
case NoPrefix if level > levelOf(tp.symbol) =>
tryHeal(tp.symbol, tp, pos)
case NoPrefix if level > levelOf(tp.symbol) && !tp.typeSymbol.hasAnnotation(defn.InternalQuoted_QuoteTypeTagAnnot) =>
val tp1 = tp.dealias
if tp1 != tp then apply(tp1)
else tryHeal(tp.symbol, tp, pos)
case prefix: ThisType if !tp.symbol.isStatic && level > levelOf(prefix.cls) =>
tryHeal(tp.symbol, tp, pos)
case prefix: TermRef if tp.symbol.isTypeSplice =>
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
val patterns1 = transform(patterns)
cpy.UnApply(tree)(transform(fun), transform(implicits), patterns1)
case tree: TypeApply =>
if tree.symbol.isQuote then
ctx.compilationUnit.needsStaging = true
val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree)
args.foreach(checkInferredWellFormed)
if (fn.symbol != defn.ChildAnnot.primaryConstructor)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class ReifyQuotes extends MacroTransform {
* core and splices as arguments.
*/
override protected def transformQuotation(body: Tree, quote: Tree)(using Context): Tree = {
val isType = quote.symbol eq defn.InternalQuoted_typeQuote
val isType = quote.symbol eq defn.QuotedTypeModule_apply
if (level > 0) {
val body1 = nested(isQuote = true).transform(body)(using quoteContext)
super.transformQuotation(body1, quote)
Expand Down Expand Up @@ -364,7 +364,7 @@ class ReifyQuotes extends MacroTransform {
transform(tree)(using ctx.withSource(tree.source))
else reporting.trace(i"Reifier.transform $tree at $level", show = true) {
tree match {
case Apply(Select(TypeApply(fn, (body: RefTree) :: Nil), _), _) if fn.symbol == defn.InternalQuoted_typeQuote && isCaptured(body.symbol, level + 1) =>
case Apply(Select(TypeApply(fn, (body: RefTree) :: Nil), _), _) if fn.symbol == defn.QuotedTypeModule_apply && isCaptured(body.symbol, level + 1) =>
// Optimization: avoid the full conversion when capturing `x`
// in '{ x } to '{ ${x$1} } and go directly to `x$1`
capturers(body.symbol)(body)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ object Splicer {
case Apply(Select(Apply(fn, quoted :: Nil), nme.apply), _) if fn.symbol == defn.InternalQuoted_exprQuote =>
// OK

case TypeApply(fn, quoted :: Nil) if fn.symbol == defn.InternalQuoted_typeQuote =>
case TypeApply(fn, quoted :: Nil) if fn.symbol == defn.QuotedTypeModule_apply =>
// OK

case Literal(Constant(value)) =>
Expand Down Expand Up @@ -231,7 +231,7 @@ object Splicer {
}
interpretQuote(quoted1)

case Apply(Select(TypeApply(fn, quoted :: Nil), _), _) if fn.symbol == defn.InternalQuoted_typeQuote =>
case Apply(Select(TypeApply(fn, quoted :: Nil), _), _) if fn.symbol == defn.QuotedTypeModule_apply =>
interpretTypeQuote(quoted)

case Literal(Constant(value)) =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/SymUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ object SymUtils {

/** Is symbol a quote operation? */
def isQuote(using Context): Boolean =
self == defn.InternalQuoted_exprQuote || self == defn.InternalQuoted_typeQuote
self == defn.InternalQuoted_exprQuote || self == defn.QuotedTypeModule_apply

/** Is symbol a term splice operation? */
def isExprSplice(using Context): Boolean =
Expand Down
11 changes: 3 additions & 8 deletions compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
case New(_) | Closure(_, _, _) =>
true
case TypeApply(fn, _) =>
if (fn.symbol.is(Erased) || fn.symbol == defn.InternalQuoted_typeQuote) true else apply(fn)
if (fn.symbol.is(Erased) || fn.symbol == defn.QuotedTypeModule_apply) true else apply(fn)
case Apply(fn, args) =>
def isKnownPureOp(sym: Symbol) =
sym.owner.isPrimitiveValueClass
Expand Down Expand Up @@ -1192,7 +1192,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
}

override def typedIdent(tree: untpd.Ident, pt: Type)(using Context): Tree =
checkStaging(tryInline(tree.asInstanceOf[tpd.Tree]) `orElse` super.typedIdent(tree, pt))
tryInline(tree.asInstanceOf[tpd.Tree]) `orElse` super.typedIdent(tree, pt)

override def typedSelect(tree: untpd.Select, pt: Type)(using Context): Tree = {
assert(tree.hasType, tree)
Expand All @@ -1204,14 +1204,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
else
val res = resMaybeReduced
ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.sourcePos)
checkStaging(res)
res
}

private def checkStaging(tree: Tree): tree.type =
if tree.symbol.isQuote then
ctx.compilationUnit.needsStaging = true
tree

override def typedIf(tree: untpd.If, pt: Type)(using Context): Tree =
typed(tree.cond, defn.BooleanType) match {
case cond1 @ ConstantValue(b: Boolean) =>
Expand Down
7 changes: 2 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ trait QuotesAndSplices {
*/
def typedQuote(tree: untpd.Quote, pt: Type)(using Context): Tree = {
record("typedQuote")
ctx.compilationUnit.needsStaging = true
tree.quoted match {
case untpd.Splice(innerExpr) if tree.isTerm =>
report.warning("Canceled splice directly inside a quote. '{ ${ XYZ } } is equivalent to XYZ.", tree.sourcePos)
Expand All @@ -59,7 +58,7 @@ trait QuotesAndSplices {
if ctx.mode.is(Mode.Pattern) then
typedQuotePattern(tree, pt, qctx)
else if (tree.quoted.isType)
typedTypeApply(untpd.TypeApply(untpd.ref(defn.InternalQuoted_typeQuote.termRef), tree.quoted :: Nil), pt)(using quoteContext).select(nme.apply).appliedTo(qctx)
typedTypeApply(untpd.TypeApply(untpd.ref(defn.QuotedTypeModule_apply.termRef), tree.quoted :: Nil), pt)(using quoteContext).select(nme.apply).appliedTo(qctx)
else
typedApply(untpd.Apply(untpd.ref(defn.InternalQuoted_exprQuote.termRef), tree.quoted), pt)(using pushQuoteContext(qctx)).select(nme.apply).appliedTo(qctx)
tree1.withSpan(tree.span)
Expand All @@ -68,7 +67,6 @@ trait QuotesAndSplices {
/** Translate `${ t: Expr[T] }` into expression `t.splice` while tracking the quotation level in the context */
def typedSplice(tree: untpd.Splice, pt: Type)(using Context): Tree = {
record("typedSplice")
ctx.compilationUnit.needsStaging = true
checkSpliceOutsideQuote(tree)
tree.expr match {
case untpd.Quote(innerExpr) if innerExpr.isTerm =>
Expand Down Expand Up @@ -147,7 +145,6 @@ trait QuotesAndSplices {
/** Translate ${ t: Type[T] }` into type `t.splice` while tracking the quotation level in the context */
def typedTypSplice(tree: untpd.TypSplice, pt: Type)(using Context): Tree = {
record("typedTypSplice")
ctx.compilationUnit.needsStaging = true
checkSpliceOutsideQuote(tree)
tree.expr match {
case untpd.Quote(innerType) if innerType.isType =>
Expand Down Expand Up @@ -442,7 +439,7 @@ trait QuotesAndSplices {
val quoteClass = if (tree.quoted.isTerm) defn.QuotedExprClass else defn.QuotedTypeClass
val quotedPattern =
if (tree.quoted.isTerm) ref(defn.InternalQuoted_exprQuote.termRef).appliedToType(defn.AnyType).appliedTo(shape).select(nme.apply).appliedTo(qctx)
else ref(defn.InternalQuoted_typeQuote.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx)
else ref(defn.QuotedTypeModule_apply.termRef).appliedToTypeTree(shape).select(nme.apply).appliedTo(qctx)
UnApply(
fun = ref(unapplySym.termRef).appliedToTypeTrees(typeBindingsTuple :: TypeTree(patType) :: Nil),
implicits = quotedPattern :: Literal(Constant(typeBindings.nonEmpty)) :: qctx :: Nil,
Expand Down
22 changes: 0 additions & 22 deletions compiler/src/dotty/tools/dotc/typer/Synthesizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,6 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
case _ => EmptyTree
end synthesizedClassTag

/** Synthesize the tree for `'[T]` for an implicit `scala.quoted.Type[T]`.
* `T` is deeply dealiased to avoid references to local type aliases.
*/
val synthesizedTypeTag: SpecialHandler = (formal, span) =>
def quotedType(t: Type) =
if StagingContext.level == 0 then
ctx.compilationUnit.needsStaging = true // We will need to run ReifyQuotes
val qctx = ctx.typer.inferImplicitArg(defn.QuoteContextClass.typeRef, span)
qctx.tpe match
case tpe: Implicits.SearchFailureType => report.error(tpe.msg, ctx.source.atSpan(span))
case _ =>
ref(defn.InternalQuoted_typeQuote).appliedToType(t).select(nme.apply).appliedTo(qctx)
formal.argInfos match
case arg :: Nil =>
val deepDealias = new TypeMap:
def apply(tp: Type): Type = mapOver(tp.dealias)
quotedType(deepDealias(arg))
case _ =>
EmptyTree
end synthesizedTypeTag

val synthesizedTupleFunction: SpecialHandler = (formal, span) =>
formal match
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
Expand Down Expand Up @@ -398,7 +377,6 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):

val specialHandlers = List(
defn.ClassTagClass -> synthesizedClassTag,
defn.QuotedTypeClass -> synthesizedTypeTag,
defn.EqlClass -> synthesizedEql,
defn.TupledFunctionClass -> synthesizedTupleFunction,
defn.ValueOfClass -> synthesizedValueOf,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ object CompileTime {
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.exprNestedSplice`")
def exprNestedSplice[T](ctx: QuoteContext)(x: ctx.Nested ?=> Expr[T]): T = ???

/** A type quote is desugared by the compiler into a call to this method */
@compileTimeOnly("Illegal reference to `scala.internal.quoted.CompileTime.typeQuote`")
def typeQuote[T <: AnyKind]: QuoteContext ?=> Type[T] = ???

/** Artifact of pickled type splices
*
* During quote reification a quote `'{ ... F[$t] ... }` will be transformed into
Expand Down
5 changes: 5 additions & 0 deletions library/src-bootstrapped/scala/quoted/Type.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package scala.quoted

import scala.annotation.compileTimeOnly
import scala.quoted.show.SyntaxHighlight

/** Quoted type (or kind) `T` */
Expand All @@ -22,6 +23,10 @@ abstract class Type[X <: AnyKind] private[scala] {
/** Some basic type tags, currently incomplete */
object Type {

/** Return a quoted.Type with the given type */
@compileTimeOnly("Reference to `scala.quoted.Type.apply` was not handled by ReifyQuotes")
given apply[T <: AnyKind] as (QuoteContext ?=> Type[T]) = ???

def UnitTag: QuoteContext ?=> Type[Unit] =
qctx.tasty.defn.UnitType.seal.asInstanceOf[quoted.Type[Unit]]

Expand Down
2 changes: 1 addition & 1 deletion tests/run-macros/i7048/Lib_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ given [U] as IsExpr[Expr[U]] = new IsExpr[Expr[U]] {

def f(x: Any): String = x.toString

def g[T](x: T)(using e: IsExpr[T], tu: Type[e.Underlying]): QuoteContext ?=> Expr[String] = {
def g[T](x: T)(using e: IsExpr[T])(using tu: Type[e.Underlying]): QuoteContext ?=> Expr[String] = {
val underlying: Expr[e.Underlying] = e.toExpr(x)
'{f($underlying)}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/run-staging/quote-nested-4.check
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
((qctx: scala.quoted.QuoteContext) ?=> {
val t: scala.quoted.Type[scala.Predef.String] = scala.internal.quoted.CompileTime.typeQuote[scala.Predef.String].apply(using qctx)
val t: scala.quoted.Type[scala.Predef.String] = scala.quoted.Type.apply[scala.Predef.String].apply(using qctx)

(t: scala.quoted.Type[scala.Predef.String])
})