summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/transform/UnCurry.scala
blob: abea8bed9fa2c3aa5f91628d5d0e9479355b0dc8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package scala
package reflect
package internal
package transform

import Flags._

trait UnCurry {

  val global: SymbolTable
  import global._
  import definitions._

  /** Note: changing tp.normalize to tp.dealias in this method leads to a single
   *  test failure: run/t5688.scala, where instead of the expected output
   *    Vector(ta, tb, tab)
   *  we instead get
   *    Vector(tab, tb, tab)
   *  I think that difference is not the product of sentience but of randomness.
   *  Let us figure out why it is and then change this method.
   */
  private def expandAlias(tp: Type): Type = if (!tp.isHigherKinded) tp.normalize else tp

  val uncurry: TypeMap = new TypeMap {
    def apply(tp0: Type): Type = {
      val tp = expandAlias(tp0)
      tp match {
        case MethodType(params, MethodType(params1, restpe)) =>
          // This transformation is described in UnCurryTransformer.dependentParamTypeErasure
          val packSymbolsMap = new TypeMap {
            // Wrapping in a TypeMap to reuse the code that opts for a fast path if the function is an identity.
            def apply(tp: Type): Type = packSymbols(params, tp)
          }
          val existentiallyAbstractedParam1s = packSymbolsMap.mapOver(params1)
          val substitutedResult = restpe.substSym(params1, existentiallyAbstractedParam1s)
          apply(MethodType(params ::: existentiallyAbstractedParam1s, substitutedResult))
        case MethodType(params, ExistentialType(tparams, restpe @ MethodType(_, _))) =>
          abort("unexpected curried method types with intervening existential")
        case MethodType(h :: t, restpe) if h.isImplicit =>
          apply(MethodType(h.cloneSymbol.resetFlag(IMPLICIT) :: t, restpe))
        case NullaryMethodType(restpe) =>
          apply(MethodType(List(), restpe))
        case TypeRef(pre, ByNameParamClass, arg :: Nil) =>
          apply(functionType(List(), arg))
        case TypeRef(pre, RepeatedParamClass, arg :: Nil) =>
          apply(seqType(arg))
        case TypeRef(pre, JavaRepeatedParamClass, arg :: Nil) =>
          apply(arrayType(
            if (isUnboundedGeneric(arg)) ObjectTpe else arg))
        case _ =>
          expandAlias(mapOver(tp))
      }
    }
  }

  private val uncurryType = new TypeMap {
    def apply(tp0: Type): Type = {
      val tp = expandAlias(tp0)
      tp match {
        case ClassInfoType(parents, decls, clazz) =>
          val parents1 = parents mapConserve uncurry
          if (parents1 eq parents) tp
          else ClassInfoType(parents1, decls, clazz) // @MAT normalize in decls??
        case PolyType(_, _) =>
          mapOver(tp)
        case _ =>
          tp
      }
    }
  }

  /** - return symbol's transformed type,
   *  - if symbol is a def parameter with transformed type T, return () => T
   *
   * @MAT: starting with this phase, the info of every symbol will be normalized
   */
  def transformInfo(sym: Symbol, tp: Type): Type =
    if (sym.isType) uncurryType(tp) else uncurry(tp)
}