Skip to content

Commit ed79907

Browse files
oderskymilessabin
authored andcommitted
Refactor special case handling in implicit arguments
1 parent 9120105 commit ed79907

File tree

1 file changed

+96
-77
lines changed

1 file changed

+96
-77
lines changed

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

Lines changed: 96 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -643,15 +643,12 @@ trait Implicits { self: Typer =>
643643
}
644644
}
645645

646-
/** Find an implicit argument for parameter `formal`.
647-
* Return a failure as a SearchFailureType in the type of the returned tree.
648-
*/
649-
def inferImplicitArg(formal: Type, span: Span)(implicit ctx: Context): Tree = {
646+
/** Handlers to synthesize implicits for special types */
647+
type SpecialHandler = (Type, Span) => Context => Tree
648+
type SpecialHandlers = List[(ClassSymbol, SpecialHandler)]
650649

651-
/** If `formal` is of the form ClassTag[T], where `T` is a class type,
652-
* synthesize a class tag for `T`.
653-
*/
654-
def synthesizedClassTag(formal: Type): Tree = formal.argInfos match {
650+
lazy val synthesizedClassTag: SpecialHandler =
651+
(formal: Type, span: Span) => implicit (ctx: Context) => formal.argInfos match {
655652
case arg :: Nil =>
656653
fullyDefinedType(arg, "ClassTag argument", span) match {
657654
case defn.ArrayOf(elemTp) =>
@@ -673,7 +670,8 @@ trait Implicits { self: Typer =>
673670
EmptyTree
674671
}
675672

676-
def synthesizedTypeTag(formal: Type): Tree = {
673+
lazy val synthesizedTypeTag: SpecialHandler =
674+
(formal: Type, span: Span) => implicit (ctx: Context) => {
677675
def quotedType(t: Type) = {
678676
if (StagingContext.level == 0)
679677
ctx.compilationUnit.needsStaging = true // We will need to run ReifyQuotes
@@ -705,59 +703,60 @@ trait Implicits { self: Typer =>
705703
}
706704
}
707705

708-
def synthesizedTastyContext(formal: Type): Tree =
706+
lazy val synthesizedTastyContext: SpecialHandler =
707+
(formal: Type, span: Span) => implicit (ctx: Context) =>
709708
if (ctx.inInlineMethod || enclosingInlineds.nonEmpty) ref(defn.TastyReflection_macroContext)
710709
else EmptyTree
711710

712-
def synthesizedTupleFunction(formal: Type): Tree = {
713-
formal match {
714-
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
715-
def functionTypeEqual(baseFun: Type, actualArgs: List[Type], actualRet: Type, expected: Type) = {
716-
expected =:= defn.FunctionOf(actualArgs, actualRet, defn.isImplicitFunctionType(baseFun), defn.isErasedFunctionType(baseFun))
717-
}
718-
val arity: Int = {
719-
if (defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun)) -1 // TODO support?
720-
else if (defn.isFunctionType(fun)) {
721-
// TupledFunction[(...) => R, ?]
722-
fun.dropDependentRefinement.dealias.argInfos match {
723-
case funArgs :+ funRet if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) =>
724-
// TupledFunction[(...funArgs...) => funRet, ?]
725-
funArgs.size
726-
case _ => -1
727-
}
728-
} else if (defn.isFunctionType(tupled)) {
729-
// TupledFunction[?, (...) => R]
730-
tupled.dropDependentRefinement.dealias.argInfos match {
731-
case tupledArgs :: funRet :: Nil =>
732-
defn.tupleTypes(tupledArgs) match {
733-
case Some(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) =>
734-
// TupledFunction[?, ((...funArgs...)) => funRet]
735-
funArgs.size
736-
case _ => -1
737-
}
738-
case _ => -1
739-
}
711+
lazy val synthesizedTupleFunction: SpecialHandler =
712+
(formal: Type, span: Span) => implicit (ctx: Context) => formal match {
713+
case AppliedType(_, funArgs @ fun :: tupled :: Nil) =>
714+
def functionTypeEqual(baseFun: Type, actualArgs: List[Type], actualRet: Type, expected: Type) = {
715+
expected =:= defn.FunctionOf(actualArgs, actualRet, defn.isImplicitFunctionType(baseFun), defn.isErasedFunctionType(baseFun))
716+
}
717+
val arity: Int = {
718+
if (defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun)) -1 // TODO support?
719+
else if (defn.isFunctionType(fun)) {
720+
// TupledFunction[(...) => R, ?]
721+
fun.dropDependentRefinement.dealias.argInfos match {
722+
case funArgs :+ funRet if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) =>
723+
// TupledFunction[(...funArgs...) => funRet, ?]
724+
funArgs.size
725+
case _ => -1
740726
}
741-
else {
742-
// TupledFunction[?, ?]
743-
-1
727+
} else if (defn.isFunctionType(tupled)) {
728+
// TupledFunction[?, (...) => R]
729+
tupled.dropDependentRefinement.dealias.argInfos match {
730+
case tupledArgs :: funRet :: Nil =>
731+
defn.tupleTypes(tupledArgs) match {
732+
case Some(funArgs) if functionTypeEqual(tupled, funArgs, funRet, fun) =>
733+
// TupledFunction[?, ((...funArgs...)) => funRet]
734+
funArgs.size
735+
case _ => -1
736+
}
737+
case _ => -1
744738
}
745739
}
746-
if (arity == -1)
747-
EmptyTree
748-
else if (arity <= Definitions.MaxImplementedFunctionArity)
749-
ref(defn.InternalTupleFunctionModule).select(s"tupledFunction$arity".toTermName).appliedToTypes(funArgs)
750-
else
751-
ref(defn.InternalTupleFunctionModule).select("tupledFunctionXXL".toTermName).appliedToTypes(funArgs)
752-
case _ =>
740+
else {
741+
// TupledFunction[?, ?]
742+
-1
743+
}
744+
}
745+
if (arity == -1)
753746
EmptyTree
754-
}
747+
else if (arity <= Definitions.MaxImplementedFunctionArity)
748+
ref(defn.InternalTupleFunctionModule).select(s"tupledFunction$arity".toTermName).appliedToTypes(funArgs)
749+
else
750+
ref(defn.InternalTupleFunctionModule).select("tupledFunctionXXL".toTermName).appliedToTypes(funArgs)
751+
case _ =>
752+
EmptyTree
755753
}
756754

757-
/** If `formal` is of the form Eql[T, U], try to synthesize an
758-
* `Eql.eqlAny[T, U]` as solution.
759-
*/
760-
def synthesizedEq(formal: Type)(implicit ctx: Context): Tree = {
755+
/** If `formal` is of the form Eql[T, U], try to synthesize an
756+
* `Eql.eqlAny[T, U]` as solution.
757+
*/
758+
lazy val synthesizedEq: SpecialHandler =
759+
(formal: Type, span: Span) => implicit (ctx: Context) => {
761760

762761
/** Is there an `Eql[T, T]` instance, assuming -strictEquality? */
763762
def hasEq(tp: Type)(implicit ctx: Context): Boolean = {
@@ -818,10 +817,11 @@ trait Implicits { self: Typer =>
818817
}
819818
}
820819

821-
/** Creates a tree that will produce a ValueOf instance for the requested type.
822-
* An EmptyTree is returned if materialization fails.
823-
*/
824-
def synthesizedValueOf(formal: Type)(implicit ctx: Context): Tree = {
820+
/** Creates a tree that will produce a ValueOf instance for the requested type.
821+
* An EmptyTree is returned if materialization fails.
822+
*/
823+
lazy val synthesizedValueOf: SpecialHandler =
824+
(formal: Type, span: Span) => implicit (ctx: Context) => {
825825
def success(t: Tree) = New(defn.ValueOfClass.typeRef.appliedTo(t.tpe), t :: Nil).withSpan(span)
826826

827827
formal.argTypes match {
@@ -841,10 +841,11 @@ trait Implicits { self: Typer =>
841841
}
842842
}
843843

844-
/** If `formal` is of the form `scala.reflect.Generic[T]` for some class type `T`,
845-
* synthesize an instance for it.
846-
*/
847-
def synthesizedGeneric(formal: Type): Tree =
844+
/** If `formal` is of the form `scala.reflect.Generic[T]` for some class type `T`,
845+
* synthesize an instance for it.
846+
*/
847+
lazy val synthesizedGeneric: SpecialHandler =
848+
(formal: Type, span: Span) => implicit (ctx: Context) =>
848849
formal.argTypes match {
849850
case arg :: Nil =>
850851
val pos = ctx.source.atSpan(span)
@@ -855,26 +856,44 @@ trait Implicits { self: Typer =>
855856
EmptyTree
856857
}
857858

859+
private var mySpecialHandlers: SpecialHandlers = null
860+
861+
private def specialHandlers(implicit ctx: Context) = {
862+
if (mySpecialHandlers == null)
863+
mySpecialHandlers = List(
864+
defn.ClassTagClass -> synthesizedClassTag,
865+
defn.QuotedTypeClass -> synthesizedTypeTag,
866+
defn.GenericClass -> synthesizedGeneric,
867+
defn.TastyReflectionClass -> synthesizedTastyContext,
868+
defn.EqlClass -> synthesizedEq,
869+
defn.TupledFunctionClass -> synthesizedTupleFunction,
870+
defn.ValueOfClass -> synthesizedValueOf
871+
)
872+
mySpecialHandlers
873+
}
874+
875+
/** Find an implicit argument for parameter `formal`.
876+
* Return a failure as a SearchFailureType in the type of the returned tree.
877+
*/
878+
def inferImplicitArg(formal: Type, span: Span)(implicit ctx: Context): Tree = {
858879
inferImplicit(formal, EmptyTree, span)(ctx) match {
859880
case SearchSuccess(arg, _, _) => arg
860881
case fail @ SearchFailure(failed) =>
861-
def trySpecialCase(cls: ClassSymbol, handler: Type => Tree, ifNot: => Tree) = {
862-
val base = formal.baseType(cls)
863-
if (base <:< formal) {
864-
// With the subtype test we enforce that the searched type `formal` is of the right form
865-
handler(base).orElse(ifNot)
866-
}
867-
else ifNot
882+
def trySpecialCases(handlers: SpecialHandlers): Tree = handlers match {
883+
case (cls, handler) :: rest =>
884+
val base = formal.baseType(cls)
885+
val result =
886+
if (base <:< formal) {
887+
// With the subtype test we enforce that the searched type `formal` is of the right form
888+
handler(base, span)(ctx)
889+
}
890+
else EmptyTree
891+
result.orElse(trySpecialCases(rest))
892+
case Nil =>
893+
failed
868894
}
869-
if (fail.isAmbiguous) failed
870-
else
871-
trySpecialCase(defn.ClassTagClass, synthesizedClassTag,
872-
trySpecialCase(defn.QuotedTypeClass, synthesizedTypeTag,
873-
trySpecialCase(defn.GenericClass, synthesizedGeneric,
874-
trySpecialCase(defn.TastyReflectionClass, synthesizedTastyContext,
875-
trySpecialCase(defn.EqlClass, synthesizedEq,
876-
trySpecialCase(defn.TupledFunctionClass, synthesizedTupleFunction,
877-
trySpecialCase(defn.ValueOfClass, synthesizedValueOf, failed)))))))
895+
if (fail.isAmbiguous) failed
896+
else trySpecialCases(specialHandlers)
878897
}
879898
}
880899

0 commit comments

Comments
 (0)