|
| 1 | +package dotty.tools.dotc |
| 2 | +package transform |
| 3 | + |
| 4 | +import ast.{Trees, tpd} |
| 5 | +import core._, core.Decorators._ |
| 6 | +import Contexts._, Trees._, Types._ |
| 7 | +import DenotTransformers._, TreeTransforms._, Phases.Phase |
| 8 | +import ExtensionMethods._, ValueClasses._ |
| 9 | + |
| 10 | +import collection.mutable.ListBuffer |
| 11 | + |
| 12 | +/** This phase inlines calls to methods of value classes. |
| 13 | + * |
| 14 | + * A value class V after [[ExtensionMethods]] will look like: |
| 15 | + * class V[A, B, ...](val underlying: U) extends AnyVal { |
| 16 | + * def foo[T, S, ...](arg1: A1, arg2: A2, ...) = |
| 17 | + * V.foo$extension[T, S, ..., A, B, ...](this)(arg1, arg2, ...) |
| 18 | + * |
| 19 | + * ... |
| 20 | + * } |
| 21 | + * |
| 22 | + * Let e have type V, if e is a stable prefix or if V does not have any class |
| 23 | + * type parameter, then we can rewrite: |
| 24 | + * e.foo[X, Y, ...](args) |
| 25 | + * as: |
| 26 | + * V.foo$extension[X, Y, ..., e.A, e.B, ...](e)(args) |
| 27 | + * Otherwise, we need to evaluate e first: |
| 28 | + * { |
| 29 | + * val ev = e |
| 30 | + * V.foo$extension[X, Y, ..., ev.A, ev.B, ...](ev)(args) |
| 31 | + * } |
| 32 | + * |
| 33 | + * This phase needs to be placed after phases which may introduce calls to |
| 34 | + * value class methods (like [[PatternMatcher]]). This phase uses name mangling |
| 35 | + * to find the correct extension method corresponding to a value class method |
| 36 | + * (see [[ExtensionMethods.extensionMethod]]), therefore we choose to place it |
| 37 | + * before phases which may perform their own name mangling on value class |
| 38 | + * methods (like [[TypeSpecializer]]), this way [[VCInlineMethods]] does not |
| 39 | + * need to have any knowledge of the name mangling done by other phases. |
| 40 | + */ |
| 41 | +class VCInlineMethods extends MiniPhaseTransform with IdentityDenotTransformer { |
| 42 | + import tpd._ |
| 43 | + |
| 44 | + override def phaseName: String = "vcInlineMethods" |
| 45 | + |
| 46 | + override def runsAfter: Set[Class[_ <: Phase]] = |
| 47 | + Set(classOf[ExtensionMethods], classOf[PatternMatcher]) |
| 48 | + |
| 49 | + /** Replace a value class method call by a call to the corresponding extension method. |
| 50 | + * |
| 51 | + * @param tree The tree corresponding to the method call |
| 52 | + * @param mtArgs Type arguments for the method call not present in `tree` |
| 53 | + * @param mArgss Arguments for the method call not present in `tree` |
| 54 | + * @return A tree for the extension method call |
| 55 | + */ |
| 56 | + private def rewire(tree: Tree, mtArgs: List[Tree] = Nil, mArgss: List[List[Tree]] = Nil) |
| 57 | + (implicit ctx: Context): Tree = |
| 58 | + tree match { |
| 59 | + case Apply(qual, mArgs) => |
| 60 | + rewire(qual, mtArgs, mArgs :: mArgss) |
| 61 | + case TypeApply(qual, mtArgs2) => |
| 62 | + assert(mtArgs == Nil) |
| 63 | + rewire(qual, mtArgs2, mArgss) |
| 64 | + case sel @ Select(qual, _) => |
| 65 | + val origMeth = sel.symbol |
| 66 | + val ctParams = origMeth.enclosingClass.typeParams |
| 67 | + val extensionMeth = extensionMethod(origMeth) |
| 68 | + |
| 69 | + if (!ctParams.isEmpty) { |
| 70 | + evalOnce(qual) { ev => |
| 71 | + val ctArgs = ctParams map (ev.select(_)) |
| 72 | + ref(extensionMeth) |
| 73 | + .appliedToTypeTrees(mtArgs ++ ctArgs) |
| 74 | + .appliedTo(ev) |
| 75 | + .appliedToArgss(mArgss) |
| 76 | + } |
| 77 | + } else { |
| 78 | + ref(extensionMeth) |
| 79 | + .appliedToTypeTrees(mtArgs) |
| 80 | + .appliedTo(qual) |
| 81 | + .appliedToArgss(mArgss) |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + /** If this tree corresponds to a fully-applied value class method call, replace it |
| 86 | + * by a call to the corresponding extension method, otherwise return it as is. |
| 87 | + */ |
| 88 | + private def rewireIfNeeded(tree: Tree)(implicit ctx: Context) = tree.tpe.widen match { |
| 89 | + case tp: MethodOrPoly => |
| 90 | + tree // The rewiring will be handled by a fully-applied parent node |
| 91 | + case _ => |
| 92 | + if (isMethodWithExtension(tree.symbol)) |
| 93 | + rewire(tree) |
| 94 | + else |
| 95 | + tree |
| 96 | + } |
| 97 | + |
| 98 | + override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = |
| 99 | + rewireIfNeeded(tree) |
| 100 | + override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = |
| 101 | + rewireIfNeeded(tree) |
| 102 | + override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = |
| 103 | + rewireIfNeeded(tree) |
| 104 | +} |
0 commit comments