Skip to content

Commit 9f4c513

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 b3aa3fe commit 9f4c513

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
@@ -553,9 +553,7 @@ trait Implicits { self: Typer =>
553553
}
554554

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

@@ -582,6 +580,81 @@ trait Implicits { self: Typer =>
582580
EmptyTree
583581
}
584582

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