Skip to content

Commit 8c1a4f5

Browse files
committed
Add type tag support
Not sure this is the right way. It feels a bit roundabout to take the detour from types to type trees. But I am not sure we can correctly quote types without trees.
1 parent 95d0c71 commit 8c1a4f5

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -554,9 +554,7 @@ trait Implicits { self: Typer =>
554554
}
555555

556556
/** Find an implicit argument for parameter `formal`.
557-
* @param error An error handler that gets an error message parameter
558-
* which is itself parameterized by another string,
559-
* indicating where the implicit parameter is needed
557+
* Return a failure as a SearchFailureType in the type of the returned tree.
560558
*/
561559
def inferImplicitArg(formal: Type, pos: Position)(implicit ctx: Context): Tree = {
562560

@@ -583,6 +581,81 @@ trait Implicits { self: Typer =>
583581
EmptyTree
584582
}
585583

584+
def synthesizedTypeTag(tpe: Type)(implicit ctx: Context): Tree = {
585+
var ok = true
586+
587+
def toParamSyms(tpe: LambdaType): List[Symbol { type ThisName = tpe.ThisName }] =
588+
(tpe.paramNames, tpe.paramInfos).zipped.map((name, bounds) =>
589+
ctx.newSymbol(ctx.owner, name, Param, bounds))
590+
591+
def toTreeAndDefs(tpe: Type): (List[TypeSymbol], List[List[TermSymbol]], Tree) = tpe match {
592+
case tpe: TypeLambda =>
593+
val tsyms = toParamSyms(tpe)
594+
val (Nil, vsymss, result) = toTreeAndDefs(tpe.resultType.substParams(tpe, tsyms.map(_.typeRef)))
595+
(tsyms, vsymss, result)
596+
case tpe: TermLambda =>
597+
val vsyms = toParamSyms(tpe)
598+
val (Nil, vsymss, result) = toTreeAndDefs(tpe.resultType.substParams(tpe, vsyms.map(_.termRef)))
599+
(Nil, vsyms :: vsymss, result)
600+
case _ =>
601+
(Nil, Nil, toTree(tpe))
602+
}
603+
604+
def refinedToTree(tpe: Type, refinements: List[Tree], refineCls: ClassSymbol): Tree = tpe.stripTypeVar match {
605+
case RefinedType(parent, rname, rinfo) =>
606+
val isMethod = rinfo.isInstanceOf[MethodOrPoly]
607+
val sym = ctx.newSymbol(refineCls, rname, if (isMethod) Method else EmptyFlags, rinfo)
608+
val refinement = rname match {
609+
case rname: TypeName =>
610+
TypeDef(sym.asType)
611+
case rname: TermName =>
612+
if (isMethod) {
613+
val (tparams, vparamss, resTpt) = toTreeAndDefs(rinfo.asInstanceOf[MethodOrPoly])
614+
DefDef(sym.asTerm, tparams, vparamss, resTpt.tpe, EmptyTree)
615+
}
616+
else ValDef(sym.asTerm)
617+
}
618+
refinedToTree(parent, refinement :: refinements, refineCls)
619+
case _ =>
620+
RefinedTypeTree(toTree(tpe), refinements, refineCls)
621+
}
622+
623+
def toTree(tpe: Type): Tree = tpe.stripTypeVar match {
624+
case tpe @ TypeRef(NoPrefix, _) =>
625+
val tag = inferImplicitArg(defn.QuotedTypeType.appliedTo(tpe), pos)
626+
ok &= !tag.tpe.isInstanceOf[SearchFailureType]
627+
tag.select(defn.QuotedType_~)
628+
case tpe: NamedType =>
629+
ref(tpe)
630+
case tpe: SingletonType =>
631+
singleton(tpe)
632+
case AppliedType(tycon, args) =>
633+
AppliedTypeTree(toTree(tycon), args.map(toTree))
634+
case AndType(l, r) =>
635+
AndTypeTree(toTree(l), toTree(r))
636+
case OrType(l, r) =>
637+
OrTypeTree(toTree(l), toTree(r))
638+
case tp: HKTypeLambda =>
639+
val tsyms = toParamSyms(tp)
640+
toTree(tp.resType.substParams(tp, tsyms.map(_.typeRef)))
641+
case tpe: RecType =>
642+
refinedToTree(tpe.parent, Nil, ctx.newRefinedClassSymbol())
643+
case tpe: RefinedType =>
644+
refinedToTree(tpe, Nil, ctx.newRefinedClassSymbol())
645+
case TypeAlias(alias) =>
646+
val aliasTree = toTree(alias)
647+
TypeBoundsTree(aliasTree, aliasTree)
648+
case TypeBounds(lo, hi) =>
649+
TypeBoundsTree(toTree(lo), toTree(hi))
650+
case _ =>
651+
EmptyTree
652+
}
653+
654+
val tag = toTree(tpe)
655+
if (ok) ref(defn.typeQuoteMethod).appliedToTypeTrees(tag :: Nil)
656+
else EmptyTree
657+
}
658+
586659
/** If `formal` is of the form Eq[T, U], where no `Eq` instance exists for
587660
* either `T` or `U`, synthesize `Eq.eqAny[T, U]` as solution.
588661
*/
@@ -645,6 +718,8 @@ trait Implicits { self: Typer =>
645718
tree
646719
else if (formalValue.isRef(defn.ClassTagClass))
647720
synthesizedClassTag(formalValue).orElse(tree)
721+
else if (formalValue.isRef(defn.QuotedTypeClass))
722+
synthesizedTypeTag(formalValue).orElse(tree)
648723
else if (formalValue.isRef(defn.EqClass))
649724
synthesizedEq(formalValue).orElse(tree)
650725
else

tests/pos/typetags.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import scala.quoted._
2+
3+
object Test {
4+
5+
def f[T: Type] = {
6+
implicitly[Type[Int]]
7+
implicitly[Type[List[Int]]]
8+
implicitly[Type[T]]
9+
implicitly[Type[List[T]]]
10+
}
11+
}

0 commit comments

Comments
 (0)