aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/ast/Desugar.scala
blob: af34164dce9de85ecaefed6dbf1a07a8ed892584 (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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
package dotty.tools
package dotc
package ast

import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, NameOps._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
import Decorators._
import language.higherKinds
import collection.mutable.ListBuffer
import util.Property
import reporting.diagnostic.messages._

object desugar {
  import untpd._

  /** Tags a .withFilter call generated by desugaring a for expression.
   *  Such calls can alternatively be rewritten to use filter.
   */
  val MaybeFilter = new Property.Key[Unit]

  /** Info of a variable in a pattern: The named tree and its type */
  private type VarInfo = (NameTree, Tree)

  /** Names of methods that are added unconditionally to case classes */
  def isDesugaredCaseClassMethodName(name: Name)(implicit ctx: Context): Boolean =
    name == nme.isDefined ||
    name == nme.copy ||
    name == nme.productArity ||
    name.isSelectorName

// ----- DerivedTypeTrees -----------------------------------

  class SetterParamTree extends DerivedTypeTree {
    def derivedType(sym: Symbol)(implicit ctx: Context) = sym.info.resultType
  }

  class TypeRefTree extends DerivedTypeTree {
    def derivedType(sym: Symbol)(implicit ctx: Context) = sym.typeRef
  }

  class DerivedFromParamTree extends DerivedTypeTree {

    /** Make sure that for all enclosing module classes their companion lasses
     *  are completed. Reason: We need the constructor of such companion classes to
     *  be completed so that OriginalSymbol attachments are pushed to DerivedTypeTrees
     *  in apply/unapply methods.
     */
    override def ensureCompletions(implicit ctx: Context) =
      if (!(ctx.owner is Package))
        if (ctx.owner.isClass) {
          ctx.owner.ensureCompleted()
          if (ctx.owner is ModuleClass)
            ctx.owner.linkedClass.ensureCompleted()
        }
        else ensureCompletions(ctx.outer)

    /** Return info of original symbol, where all references to siblings of the
     *  original symbol (i.e. sibling and original symbol have the same owner)
     *  are rewired to same-named parameters or accessors in the scope enclosing
     *  the current scope. The current scope is the scope owned by the defined symbol
     *  itself, that's why we have to look one scope further out. If the resulting
     *  type is an alias type, dealias it. This is necessary because the
     *  accessor of a type parameter is a private type alias that cannot be accessed
     *  from subclasses.
     */
    def derivedType(sym: Symbol)(implicit ctx: Context) = {
      val relocate = new TypeMap {
        val originalOwner = sym.owner
        def apply(tp: Type) = tp match {
          case tp: NamedType if tp.symbol.exists && (tp.symbol.owner eq originalOwner) =>
            val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next
            var local = defctx.denotNamed(tp.name).suchThat(_ is ParamOrAccessor).symbol
            if (local.exists) (defctx.owner.thisType select local).dealias
            else throw new java.lang.Error(
              s"no matching symbol for ${tp.symbol.showLocated} in ${defctx.owner} / ${defctx.effectiveScope}"
            )
          case _ =>
            mapOver(tp)
        }
      }
      relocate(sym.info)
    }
  }

  /** A type definition copied from `tdef` with a rhs typetree derived from it */
  def derivedTypeParam(tdef: TypeDef) =
    cpy.TypeDef(tdef)(
      rhs = new DerivedFromParamTree() withPos tdef.rhs.pos watching tdef)

  /** A value definition copied from `vdef` with a tpt typetree derived from it */
  def derivedTermParam(vdef: ValDef) =
    cpy.ValDef(vdef)(
      tpt = new DerivedFromParamTree() withPos vdef.tpt.pos watching vdef)

// ----- Desugar methods -------------------------------------------------

  /**   var x: Int = expr
   *  ==>
   *    def x: Int = expr
   *    def x_=($1: <TypeTree()>): Unit = ()
   */
  def valDef(vdef: ValDef)(implicit ctx: Context): Tree = {
    val ValDef(name, tpt, rhs) = vdef
    val mods = vdef.mods
    def setterNeeded =
      (mods is Mutable) && ctx.owner.isClass && (!(mods is PrivateLocal) || (ctx.owner is Trait))
    if (setterNeeded) {
      // todo: copy of vdef as getter needed?
      // val getter = ValDef(mods, name, tpt, rhs) withPos vdef.pos ?
      // right now vdef maps via expandedTree to a thicket which concerns itself.
      // I don't see a problem with that but if there is one we can avoid it by making a copy here.
      val setterParam = makeSyntheticParameter(tpt = (new SetterParamTree).watching(vdef))
      val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral
      val setter = cpy.DefDef(vdef)(
        name = name.setterName,
        tparams = Nil,
        vparamss = (setterParam :: Nil) :: Nil,
        tpt = TypeTree(defn.UnitType),
        rhs = setterRhs
      ).withMods((mods | Accessor) &~ CaseAccessor) // rhs gets filled in later, when field is generated and getter has parameters
      Thicket(vdef, setter)
    }
    else vdef
  }

  /** Expand context bounds to evidence params. E.g.,
   *
   *      def f[T >: L <: H : B](params)
   *  ==>
   *      def f[T >: L <: H](params)(implicit evidence$0: B[T])
   *
   *  Expand default arguments to default getters. E.g,
   *
   *      def f[T: B](x: Int = 1)(y: String = x + "m") = ...
   *  ==>
   *      def f[T](x: Int)(y: String)(implicit evidence$0: B[T]) = ...
   *      def f$default$1[T] = 1
   *      def f$default$2[T](x: Int) = x + "m"
   */
  def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
    val DefDef(name, tparams, vparamss, tpt, rhs) = meth
    val mods = meth.mods
    val epbuf = new ListBuffer[ValDef]
    val tparams1 = tparams mapConserve {
      case tparam @ TypeDef(_, ContextBounds(tbounds, cxbounds)) =>
        for (cxbound <- cxbounds) {
          val paramFlags: FlagSet = if (isPrimaryConstructor) PrivateLocalParamAccessor else Param
          val epname = ctx.freshName(nme.EVIDENCE_PARAM_PREFIX).toTermName
          epbuf += ValDef(epname, cxbound, EmptyTree).withFlags(paramFlags | Implicit)
        }
        cpy.TypeDef(tparam)(rhs = tbounds)
      case tparam =>
        tparam
    }

    val meth1 = addEvidenceParams(cpy.DefDef(meth)(tparams = tparams1), epbuf.toList)

    /** The longest prefix of parameter lists in vparamss whose total length does not exceed `n` */
    def takeUpTo(vparamss: List[List[ValDef]], n: Int): List[List[ValDef]] = vparamss match {
      case vparams :: vparamss1 =>
        val len = vparams.length
        if (n >= len) vparams :: takeUpTo(vparamss1, n - len) else Nil
      case _ =>
        Nil
    }

    def normalizedVparamss = meth1.vparamss map (_ map (vparam =>
      cpy.ValDef(vparam)(rhs = EmptyTree)))

    def dropContextBound(tparam: TypeDef) = tparam.rhs match {
      case ContextBounds(tbounds, _) => cpy.TypeDef(tparam)(rhs = tbounds)
      case _ => tparam
    }

    def defaultGetters(vparamss: List[List[ValDef]], n: Int): List[DefDef] = vparamss match {
      case (vparam :: vparams) :: vparamss1 =>
        def defaultGetter: DefDef =
          DefDef(
            name = meth.name.defaultGetterName(n),
            tparams = meth.tparams.map(tparam => dropContextBound(toDefParam(tparam))),
            vparamss = takeUpTo(normalizedVparamss, n),
            tpt = TypeTree(),
            rhs = vparam.rhs
          ).withMods(Modifiers(mods.flags & AccessFlags, mods.privateWithin))
        val rest = defaultGetters(vparams :: vparamss1, n + 1)
        if (vparam.rhs.isEmpty) rest else defaultGetter :: rest
      case Nil :: vparamss1 =>
        defaultGetters(vparamss1, n)
      case nil =>
        Nil
    }

    val defGetters = defaultGetters(vparamss, 0)
    if (defGetters.isEmpty) meth1
    else {
      val meth2 = cpy.DefDef(meth1)(vparamss = normalizedVparamss)
        .withMods(meth1.mods | DefaultParameterized)
      Thicket(meth2 :: defGetters)
    }
  }

  // Add all evidence parameters in `params` as implicit parameters to `meth` */
  private def addEvidenceParams(meth: DefDef, params: List[ValDef])(implicit ctx: Context): DefDef =
    params match {
      case Nil =>
        meth
      case evidenceParams =>
        val vparamss1 = meth.vparamss.reverse match {
          case (vparams @ (vparam :: _)) :: rvparamss if vparam.mods is Implicit =>
            ((vparams ++ evidenceParams) :: rvparamss).reverse
          case _ =>
            meth.vparamss :+ evidenceParams
        }
        cpy.DefDef(meth)(vparamss = vparamss1)
    }

  /** The implicit evidence parameters of `meth`, as generated by `desugar.defDef` */
  private def evidenceParams(meth: DefDef)(implicit ctx: Context): List[ValDef] =
    meth.vparamss.reverse match {
      case (vparams @ (vparam :: _)) :: _ if vparam.mods is Implicit =>
        vparams.dropWhile(!_.name.startsWith(nme.EVIDENCE_PARAM_PREFIX))
      case _ =>
        Nil
    }

  /** Fill in empty type bounds with Nothing/Any. Expand private local type parameters as follows:
   *
   *     class C[v T]
   * ==>
   *     class C { type v C$T; type v T = C$T }
   */
  def typeDef(tdef: TypeDef)(implicit ctx: Context): Tree = {
    if (tdef.mods is PrivateLocalParam) {
      val tparam = cpy.TypeDef(tdef)(name = tdef.name.expandedName(ctx.owner))
        .withMods(tdef.mods &~ PrivateLocal | ExpandedName)
      val alias = cpy.TypeDef(tdef)(rhs = refOfDef(tparam), tparams = Nil)
        .withMods(tdef.mods & VarianceFlags | PrivateLocalParamAccessor | Synthetic)
      Thicket(tparam, alias)
    }
    else tdef
  }

  @sharable private val synthetic = Modifiers(Synthetic)

  private def toDefParam(tparam: TypeDef): TypeDef =
    tparam.withMods(tparam.rawMods & EmptyFlags | Param)
  private def toDefParam(vparam: ValDef): ValDef =
    vparam.withMods(vparam.rawMods & Implicit | Param)

  /** The expansion of a class definition. See inline comments for what is involved */
  def classDef(cdef: TypeDef)(implicit ctx: Context): Tree = {
    val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef
    val mods = cdef.mods
    val companionMods = mods.withFlags((mods.flags & AccessFlags).toCommonFlags)

    val (constr1, defaultGetters) = defDef(constr0, isPrimaryConstructor = true) match {
      case meth: DefDef => (meth, Nil)
      case Thicket((meth: DefDef) :: defaults) => (meth, defaults)
    }

    // The original type and value parameters in the constructor already have the flags
    // needed to be type members (i.e. param, and possibly also private and local unless
    // prefixed by type or val). `tparams` and `vparamss` are the type parameters that
    // go in `constr`, the constructor after desugaring.

    /** Does `tree' look like a reference to AnyVal? Temporary test before we have inline classes */
    def isAnyVal(tree: Tree): Boolean = tree match {
      case Ident(tpnme.AnyVal) => true
      case Select(qual, tpnme.AnyVal) => isScala(qual)
      case _ => false
    }
    def isScala(tree: Tree): Boolean = tree match {
      case Ident(nme.scala_) => true
      case Select(Ident(nme.ROOTPKG), nme.scala_) => true
      case _ => false
    }

    val isCaseClass = mods.is(Case) && !mods.is(Module)
    val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
      // This is not watertight, but `extends AnyVal` will be replaced by `inline` later.

    val constrTparams = constr1.tparams map toDefParam
    val constrVparamss =
      if (constr1.vparamss.isEmpty) { // ensure parameter list is non-empty
        if (isCaseClass)
          ctx.error(CaseClassMissingParamList(cdef), cdef.namePos)
        ListOfNil
      }
      else constr1.vparamss.nestedMap(toDefParam)
    val constr = cpy.DefDef(constr1)(tparams = constrTparams, vparamss = constrVparamss)

    // Add constructor type parameters and evidence implicit parameters
    // to auxiliary constructors
    val normalizedBody = impl.body map {
      case ddef: DefDef if ddef.name.isConstructorName =>
        addEvidenceParams(
          cpy.DefDef(ddef)(tparams = constrTparams),
          evidenceParams(constr1).map(toDefParam))
      case stat =>
        stat
    }

    val derivedTparams = constrTparams map derivedTypeParam
    val derivedVparamss = constrVparamss nestedMap derivedTermParam
    val arity = constrVparamss.head.length

    var classTycon: Tree = EmptyTree

    // a reference to the class type, with all parameters given.
    val classTypeRef/*: Tree*/ = {
        // -language:keepUnions difference: classTypeRef needs type annotation, otherwise
        // infers Ident | AppliedTypeTree, which
        // renders the :\ in companions below untypable.
      classTycon = (new TypeRefTree) withPos cdef.pos.startPos // watching is set at end of method
      val tparams = impl.constr.tparams
      if (tparams.isEmpty) classTycon else AppliedTypeTree(classTycon, tparams map refOfDef)
    }

    // new C[Ts](paramss)
    lazy val creatorExpr = New(classTypeRef, constrVparamss nestedMap refOfDef)

    // Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams)
    //     def isDefined = true
    //     def productArity = N
    //     def _1 = this.p1
    //     ...
    //     def _N = this.pN
    //     def copy(p1: T1 = p1: @uncheckedVariance, ...,
    //              pN: TN = pN: @uncheckedVariance)(moreParams) =
    //       new C[...](p1, ..., pN)(moreParams)
    //
    // Note: copy default parameters need @uncheckedVariance; see
    // neg/t1843-variances.scala for a test case. The test would give
    // two errors without @uncheckedVariance, one of them spurious.
    val caseClassMeths =
      if (isCaseClass) {
        def syntheticProperty(name: TermName, rhs: Tree) =
          DefDef(name, Nil, Nil, TypeTree(), rhs).withMods(synthetic)
        val isDefinedMeth = syntheticProperty(nme.isDefined, Literal(Constant(true)))
        val caseParams = constrVparamss.head.toArray
        val productElemMeths = for (i <- 0 until arity) yield
          syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeName), caseParams(i).name))
        def isRepeated(tree: Tree): Boolean = tree match {
          case PostfixOp(_, nme.raw.STAR) => true
          case ByNameTypeTree(tree1) => isRepeated(tree1)
          case _ => false
        }
        val hasRepeatedParam = constrVparamss.exists(_.exists {
          case ValDef(_, tpt, _) => isRepeated(tpt)
          case _ => false
        })

        val copyMeths =
          if (mods.is(Abstract) || hasRepeatedParam) Nil  // cannot have default arguments for repeated parameters, hence copy method is not issued
          else {
            def copyDefault(vparam: ValDef) =
              makeAnnotated(defn.UncheckedVarianceAnnot, refOfDef(vparam))
            val copyFirstParams = derivedVparamss.head.map(vparam =>
              cpy.ValDef(vparam)(rhs = copyDefault(vparam)))
            val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
              cpy.ValDef(vparam)(rhs = EmptyTree))
            DefDef(nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr)
              .withMods(synthetic) :: Nil
          }
        copyMeths ::: isDefinedMeth :: productElemMeths.toList
      }
      else Nil

    def anyRef = ref(defn.AnyRefAlias.typeRef)
    def productConstr(n: Int) = {
      val tycon = scalaDot((tpnme.Product.toString + n).toTypeName)
      val targs = constrVparamss.head map (_.tpt)
      if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs)
    }

    // Case classes and case objects get a ProductN parent
    var parents1 = parents
    if (mods.is(Case) && arity <= Definitions.MaxTupleArity)
      parents1 = parents1 :+ productConstr(arity)

    // The thicket which is the desugared version of the companion object
    //     synthetic object C extends parentTpt { defs }
    def companionDefs(parentTpt: Tree, defs: List[Tree]) =
      moduleDef(
        ModuleDef(
          name.toTermName, Template(emptyConstructor, parentTpt :: Nil, EmptyValDef, defs))
            .withMods(companionMods | Synthetic))
      .withPos(cdef.pos).toList

    // The companion object definitions, if a companion is needed, Nil otherwise.
    // companion definitions include:
    // 1. If class is a case class case class C[Ts](p1: T1, ..., pN: TN)(moreParams):
    //     def apply[Ts](p1: T1, ..., pN: TN)(moreParams) = new C[Ts](p1, ..., pN)(moreParams)  (unless C is abstract)
    //     def unapply[Ts]($1: C[Ts]) = $1
    // 2. The default getters of the constructor
    // The parent of the companion object of a non-parameterized case class
    //     (T11, ..., T1N) => ... => (TM1, ..., TMN) => C
    // For all other classes, the parent is AnyRef.
    val companions =
      if (isCaseClass) {
        val parent =
          if (constrTparams.nonEmpty ||
              constrVparamss.length > 1 ||
              mods.is(Abstract) ||
              constr.mods.is(Private)) anyRef
            // todo: also use anyRef if constructor has a dependent method type (or rule that out)!
          else (constrVparamss :\ classTypeRef) ((vparams, restpe) => Function(vparams map (_.tpt), restpe))
        val applyMeths =
          if (mods is Abstract) Nil
          else
            DefDef(nme.apply, derivedTparams, derivedVparamss, TypeTree(), creatorExpr)
              .withFlags(Synthetic | (constr1.mods.flags & DefaultParameterized)) :: Nil
        val unapplyMeth = {
          val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
          val unapplyRHS = if (arity == 0) Literal(Constant(true)) else Ident(unapplyParam.name)
          DefDef(nme.unapply, derivedTparams, (unapplyParam :: Nil) :: Nil, TypeTree(), unapplyRHS)
            .withMods(synthetic)
        }
        companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters)
      }
      else if (defaultGetters.nonEmpty)
        companionDefs(anyRef, defaultGetters)
      else if (isValueClass)
        companionDefs(anyRef, Nil)
      else Nil


    // For an implicit class C[Ts](p11: T11, ..., p1N: T1N) ... (pM1: TM1, .., pMN: TMN), the method
    //     synthetic implicit C[Ts](p11: T11, ..., p1N: T1N) ... (pM1: TM1, ..., pMN: TMN): C[Ts] =
    //       new C[Ts](p11, ..., p1N) ... (pM1, ..., pMN) =
    val implicitWrappers =
      if (!mods.is(Implicit))
        Nil
      else if (ctx.owner is Package) {
        ctx.error("implicit classes may not be toplevel", cdef.pos)
        Nil
      }
      else if (isCaseClass) {
        ctx.error("implicit classes may not be case classes", cdef.pos)
        Nil
      }
      else
        // implicit wrapper is typechecked in same scope as constructor, so
        // we can reuse the constructor parameters; no derived params are needed.
        DefDef(name.toTermName, constrTparams, constrVparamss, classTypeRef, creatorExpr)
          .withMods(companionMods | Synthetic | Implicit)
          .withPos(cdef.pos) :: Nil

    val self1 = {
      val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt
      if (self.isEmpty) self
      else cpy.ValDef(self)(tpt = selfType).withMods(self.mods | SelfName)
    }

    val cdef1 = {
      val originalTparams = constr1.tparams.toIterator
      val originalVparams = constr1.vparamss.toIterator.flatten
      val tparamAccessors = derivedTparams.map(_.withMods(originalTparams.next.mods))
      val caseAccessor = if (isCaseClass) CaseAccessor else EmptyFlags
      val vparamAccessors = derivedVparamss.flatten.map(_.withMods(originalVparams.next.mods | caseAccessor))
      cpy.TypeDef(cdef)(
        rhs = cpy.Template(impl)(constr, parents1, self1,
          tparamAccessors ::: vparamAccessors ::: normalizedBody ::: caseClassMeths),
        tparams = Nil)
    }

    // install the watch on classTycon
    classTycon match {
      case tycon: DerivedTypeTree => tycon.watching(cdef1)
      case _ =>
    }

    flatTree(cdef1 :: companions ::: implicitWrappers)
  }

  val AccessOrSynthetic = AccessFlags | Synthetic

  /** Expand
   *
   *    object name extends parents { self => body }
   *
   *  to:
   *    <module> val name: name$ = New(name$)
   *    <module> final class name$ extends parents { self: name.type => body }
   */
  def moduleDef(mdef: ModuleDef)(implicit ctx: Context): Tree = {
    val ModuleDef(name, tmpl) = mdef
    val mods = mdef.mods
    if (mods is Package)
      PackageDef(Ident(name), cpy.ModuleDef(mdef)(nme.PACKAGE, tmpl).withMods(mods &~ Package) :: Nil)
    else {
      val clsName = name.moduleClassName
      val clsRef = Ident(clsName)
      val modul = ValDef(name, clsRef, New(clsRef, Nil))
        .withMods(mods | ModuleCreationFlags | mods.flags & AccessFlags)
        .withPos(mdef.pos)
      val ValDef(selfName, selfTpt, _) = tmpl.self
      val selfMods = tmpl.self.mods
      if (!selfTpt.isEmpty) ctx.error("object definition may not have a self type", tmpl.self.pos)
      val clsSelf = ValDef(selfName, SingletonTypeTree(Ident(name)), tmpl.self.rhs)
        .withMods(selfMods)
        .withPos(tmpl.self.pos orElse tmpl.pos.startPos)
      val clsTmpl = cpy.Template(tmpl)(self = clsSelf, body = tmpl.body)
      val cls = TypeDef(clsName, clsTmpl)
        .withMods(mods.toTypeFlags & RetainedModuleClassFlags | ModuleClassCreationFlags)
      Thicket(modul, classDef(cls).withPos(mdef.pos))
    }
  }

  /**     val p1, ..., pN: T = E
   *  ==>
   *      makePatDef[[val p1: T1 = E]]; ...; makePatDef[[val pN: TN = E]]
   */
  def patDef(pdef: PatDef)(implicit ctx: Context): Tree = {
    val PatDef(mods, pats, tpt, rhs) = pdef
    val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
    flatTree(pats1 map (makePatDef(pdef, mods, _, rhs)))
  }

  /** If `pat` is a variable pattern,
   *
   *    val/var/lazy val p = e
   *
   *  Otherwise, in case there is exactly one variable x_1 in pattern
   *   val/var/lazy val p = e  ==>  val/var/lazy val x_1 = (e: @unchecked) match (case p => (x_1))
   *
   *   in case there are zero or more than one variables in pattern
   *   val/var/lazy p = e  ==>  private synthetic [lazy] val t$ = (e: @unchecked) match (case p => (x_1, ..., x_N))
   *                   val/var/def x_1 = t$._1
   *                   ...
   *                   val/var/def x_N = t$._N
   *  If the original pattern variable carries a type annotation, so does the corresponding
   *  ValDef or DefDef.
   */
  def makePatDef(original: Tree, mods: Modifiers, pat: Tree, rhs: Tree)(implicit ctx: Context): Tree = pat match {
    case VarPattern(named, tpt) =>
      derivedValDef(original, named, tpt, rhs, mods)
    case _ =>
      val rhsUnchecked = makeAnnotated(defn.UncheckedAnnot, rhs)
      val vars = getVariables(pat)
      val isMatchingTuple: Tree => Boolean = {
        case Tuple(es) => es.length == vars.length
        case _ => false
      }
      val ids = for ((named, _) <- vars) yield Ident(named.name)
      val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids))
      val matchExpr =
        if (forallResults(rhs, isMatchingTuple)) rhs
        else Match(rhsUnchecked, caseDef :: Nil)
      vars match {
        case Nil =>
          matchExpr
        case (named, tpt) :: Nil =>
          derivedValDef(original, named, tpt, matchExpr, mods)
        case _ =>
          val tmpName = ctx.freshName().toTermName
          val patMods = mods & (AccessFlags | Lazy) | Synthetic
          val firstDef =
            ValDef(tmpName, TypeTree(), matchExpr)
              .withPos(pat.pos.union(rhs.pos)).withMods(patMods)
          def selector(n: Int) = Select(Ident(tmpName), nme.selectorName(n))
          val restDefs =
            for (((named, tpt), n) <- vars.zipWithIndex)
            yield
              if (mods is Lazy) derivedDefDef(original, named, tpt, selector(n), mods &~ Lazy)
              else derivedValDef(original, named, tpt, selector(n), mods)
          flatTree(firstDef :: restDefs)
      }
  }

  /** Expand variable identifier x to x @ _ */
  def patternVar(tree: Tree)(implicit ctx: Context) = {
    val Ident(name) = tree
    Bind(name, Ident(nme.WILDCARD)).withPos(tree.pos)
  }

  def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
    case tree: ValDef => valDef(tree)
    case tree: TypeDef => if (tree.isClassDef) classDef(tree) else typeDef(tree)
    case tree: DefDef => defDef(tree)
    case tree: ModuleDef => moduleDef(tree)
    case tree: PatDef => patDef(tree)
  }

  /**     { stats; <empty > }
   *  ==>
   *      { stats; () }
   */
  def block(tree: Block)(implicit ctx: Context): Block = tree.expr match {
    case EmptyTree =>
      cpy.Block(tree)(tree.stats,
        unitLiteral withPos (if (tree.stats.isEmpty) tree.pos else tree.pos.endPos))
    case _ =>
      tree
  }

  /** EmptyTree in lower bound ==> Nothing
   *  EmptyTree in upper bounds ==> Any
   */
  def typeBoundsTree(tree: TypeBoundsTree)(implicit ctx: Context): TypeBoundsTree = {
    val TypeBoundsTree(lo, hi) = tree
    val lo1 = if (lo.isEmpty) untpd.TypeTree(defn.NothingType) else lo
    val hi1 = if (hi.isEmpty) untpd.TypeTree(defn.AnyType) else hi
    cpy.TypeBoundsTree(tree)(lo1, hi1)
  }

  /** Make closure corresponding to function.
   *      params => body
   *  ==>
   *      def $anonfun(params) = body
   *      Closure($anonfun)
   *
   *  If `inlineable` is true, tag $anonfun with an @inline annotation.
   */
  def makeClosure(params: List[ValDef], body: Tree, tpt: Tree = TypeTree(), inlineable: Boolean)(implicit ctx: Context) = {
    var mods = synthetic
    if (inlineable)
      mods = mods.withAddedAnnotation(New(ref(defn.InlineAnnotType), Nil).withPos(body.pos))
    Block(
      DefDef(nme.ANON_FUN, Nil, params :: Nil, tpt, body).withMods(mods),
      Closure(Nil, Ident(nme.ANON_FUN), EmptyTree))
  }

  /** If `nparams` == 1, expand partial function
   *
   *       { cases }
   *  ==>
   *       x$1 => (x$1 @unchecked) match { cases }
   *
   *  If `nparams` != 1, expand instead to
   *
   *       (x$1, ..., x$n) => (x$0, ..., x${n-1} @unchecked) match { cases }
   */
  def makeCaseLambda(cases: List[CaseDef], nparams: Int = 1, unchecked: Boolean = true)(implicit ctx: Context) = {
    val params = (1 to nparams).toList.map(makeSyntheticParameter(_))
    val selector = makeTuple(params.map(p => Ident(p.name)))

    if (unchecked)
      Function(params, Match(Annotated(selector, New(ref(defn.UncheckedAnnotType))), cases))
    else
      Function(params, Match(selector, cases))
  }

  /** Map n-ary function `(p1, ..., pn) => body` where n != 1 to unary function as follows:
   *
   *    x$1 => {
   *      def p1 = x$1._1
   *      ...
   *      def pn = x$1._n
   *      body
   *    }
   */
  def makeTupledFunction(params: List[ValDef], body: Tree)(implicit ctx: Context): Tree = {
    val param = makeSyntheticParameter()
    def selector(n: Int) = Select(refOfDef(param), nme.selectorName(n))
    val vdefs =
      params.zipWithIndex.map{
        case (param, idx) =>
          DefDef(param.name, Nil, Nil, TypeTree(), selector(idx)).withPos(param.pos)
      }
    Function(param :: Nil, Block(vdefs, body))
  }

  /** Add annotation with class `cls` to tree:
   *      tree @cls
   */
  def makeAnnotated(cls: Symbol, tree: Tree)(implicit ctx: Context) =
    Annotated(tree, untpd.New(untpd.TypeTree(cls.typeRef), Nil))

  private def derivedValDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers)(implicit ctx: Context) = {
    val vdef = ValDef(named.name.asTermName, tpt, rhs)
      .withMods(mods)
      .withPos(original.pos.withPoint(named.pos.start))
    val mayNeedSetter = valDef(vdef)
    mayNeedSetter
   }

  private def derivedDefDef(original: Tree, named: NameTree, tpt: Tree, rhs: Tree, mods: Modifiers) =
    DefDef(named.name.asTermName, Nil, Nil, tpt, rhs)
      .withMods(mods)
      .withPos(original.pos.withPoint(named.pos.start))

  /** Main desugaring method */
  def apply(tree: Tree)(implicit ctx: Context): Tree = {

    /**    { label def lname(): Unit = rhs; call }
     */
    def labelDefAndCall(lname: TermName, rhs: Tree, call: Tree) = {
      val ldef = DefDef(lname, Nil, ListOfNil, TypeTree(defn.UnitType), rhs).withFlags(Label)
      Block(ldef, call)
    }

    /** Translate infix operation expression  left op right
     */
    def makeBinop(left: Tree, op: Name, right: Tree): Tree = {
      def assignToNamedArg(arg: Tree) = arg match {
        case Assign(Ident(name), rhs) => cpy.NamedArg(arg)(name, rhs)
        case _ => arg
      }
      if (isLeftAssoc(op)) {
        val args: List[Tree] = right match {
          case Parens(arg) => assignToNamedArg(arg) :: Nil
          case Tuple(args) => args mapConserve assignToNamedArg
          case _ => right :: Nil
        }
        Apply(Select(left, op), args)
      } else {
        val x = ctx.freshName().toTermName
        new InfixOpBlock(
          ValDef(x, TypeTree(), left).withMods(synthetic),
          Apply(Select(right, op), Ident(x)))
      }
    }

    /** Create tree for for-comprehension `<for (enums) do body>` or
     *   `<for (enums) yield body>` where mapName and flatMapName are chosen
     *  corresponding to whether this is a for-do or a for-yield.
     *  The creation performs the following rewrite rules:
     *
     *  1.
     *
     *    for (P <- G) E   ==>   G.foreach (P => E)
     *
     *     Here and in the following (P => E) is interpreted as the function (P => E)
     *     if P is a variable pattern and as the partial function { case P => E } otherwise.
     *
     *  2.
     *
     *    for (P <- G) yield E  ==>  G.map (P => E)
     *
     *  3.
     *
     *    for (P_1 <- G_1; P_2 <- G_2; ...) ...
     *      ==>
     *    G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
     *
     *  4.
     *
     *    for (P <- G; E; ...) ...
     *      =>
     *    for (P <- G.filter (P => E); ...) ...
     *
     *  5. For any N:
     *
     *    for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...)
     *      ==>
     *    for (TupleN(P_1, P_2, ... P_N) <-
     *      for (x_1 @ P_1 <- G) yield {
     *        val x_2 @ P_2 = E_2
     *        ...
     *        val x_N & P_N = E_N
     *        TupleN(x_1, ..., x_N)
     *      } ...)
     *
     *    If any of the P_i are variable patterns, the corresponding `x_i @ P_i` is not generated
     *    and the variable constituting P_i is used instead of x_i
     *
     *  @param mapName      The name to be used for maps (either map or foreach)
     *  @param flatMapName  The name to be used for flatMaps (either flatMap or foreach)
     *  @param enums        The enumerators in the for expression
     *  @param body         The body of the for expression
     */
    def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Tree], body: Tree): Tree = ctx.traceIndented(i"make for ${ForYield(enums, body)}", show = true) {

      /** Make a function value pat => body.
       *  If pat is a var pattern id: T then this gives (id: T) => body
       *  Otherwise this gives { case pat => body }
       */
      def makeLambda(pat: Tree, body: Tree): Tree = pat match {
        case VarPattern(named, tpt) =>
          Function(derivedValDef(pat, named, tpt, EmptyTree, Modifiers(Param)) :: Nil, body)
        case _ =>
          makeCaseLambda(CaseDef(pat, EmptyTree, body) :: Nil, unchecked = false)
      }

      /** If `pat` is not an Identifier, a Typed(Ident, _), or a Bind, wrap
       *  it in a Bind with a fresh name. Return the transformed pattern, and the identifier
       *  that refers to the bound variable for the pattern.
       */
      def makeIdPat(pat: Tree): (Tree, Ident) = pat match {
        case Bind(name, _) => (pat, Ident(name))
        case id: Ident if isVarPattern(id) && id.name != nme.WILDCARD => (id, id)
        case Typed(id: Ident, _) if isVarPattern(id) && id.name != nme.WILDCARD => (pat, id)
        case _ =>
          val name = ctx.freshName().toTermName
          (Bind(name, pat), Ident(name))
      }

      /** Add MaybeFilter attachment */
      def orFilter(tree: Tree): tree.type = {
        tree.putAttachment(MaybeFilter, ())
        tree
      }

      /** Make a pattern filter:
       *    rhs.withFilter { case pat => true case _ => false }
       *
       *  On handling irrefutable patterns:
       *  The idea is to wait until the pattern matcher sees a call
       *
       *      xs withFilter { cases }
       *
       *  where cases can be proven to be refutable i.e. cases would be
       *  equivalent to  { case _ => true }
       *
       *  In that case, compile to
       *
       *      xs withFilter alwaysTrue
       *
       *  where `alwaysTrue` is a predefined function value:
       *
       *      val alwaysTrue: Any => Boolean = true
       *
       *  In the libraries operations can take advantage of alwaysTrue to shortcircuit the
       *  withFilter call.
       *
       *  def withFilter(f: Elem => Boolean) =
       *    if (f eq alwaysTrue) this // or rather identity filter monadic applied to this
       *    else real withFilter
       */
      def makePatFilter(rhs: Tree, pat: Tree): Tree = {
        val cases = List(
          CaseDef(pat, EmptyTree, Literal(Constant(true))),
          CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))))
        Apply(orFilter(Select(rhs, nme.withFilter)), makeCaseLambda(cases))
      }

      /** Is pattern `pat` irrefutable when matched against `rhs`?
       *  We only can do a simple syntactic check here; a more refined check
       *  is done later in the pattern matcher (see discussion in @makePatFilter).
       */
      def isIrrefutable(pat: Tree, rhs: Tree): Boolean = {
        def matchesTuple(pats: List[Tree], rhs: Tree): Boolean = rhs match {
          case Tuple(trees) => (pats corresponds trees)(isIrrefutable)
          case Parens(rhs1) => matchesTuple(pats, rhs1)
          case Block(_, rhs1) => matchesTuple(pats, rhs1)
          case If(_, thenp, elsep) => matchesTuple(pats, thenp) && matchesTuple(pats, elsep)
          case Match(_, cases) => cases forall (matchesTuple(pats, _))
          case CaseDef(_, _, rhs1) => matchesTuple(pats, rhs1)
          case Throw(_) => true
          case _ => false
        }
        pat match {
          case Bind(_, pat1) => isIrrefutable(pat1, rhs)
          case Parens(pat1) => isIrrefutable(pat1, rhs)
          case Tuple(pats) => matchesTuple(pats, rhs)
          case _ => isVarPattern(pat)
        }
      }

      def isIrrefutableGenFrom(gen: GenFrom): Boolean =
        gen.isInstanceOf[IrrefutableGenFrom] || isIrrefutable(gen.pat, gen.expr)

      /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when
       *  matched against `rhs`.
       */
      def rhsSelect(gen: GenFrom, name: TermName) = {
        val rhs = if (isIrrefutableGenFrom(gen)) gen.expr else makePatFilter(gen.expr, gen.pat)
        Select(rhs, name)
      }

      enums match {
        case (gen: GenFrom) :: Nil =>
          Apply(rhsSelect(gen, mapName), makeLambda(gen.pat, body))
        case (gen: GenFrom) :: (rest @ (GenFrom(_, _) :: _)) =>
          val cont = makeFor(mapName, flatMapName, rest, body)
          Apply(rhsSelect(gen, flatMapName), makeLambda(gen.pat, cont))
        case (enum @ GenFrom(pat, rhs)) :: (rest @ GenAlias(_, _) :: _) =>
          val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
          val pats = valeqs map { case GenAlias(pat, _) => pat }
          val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
          val (defpat0, id0) = makeIdPat(pat)
          val (defpats, ids) = (pats map makeIdPat).unzip
          val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers(), _, _))
          val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
          val allpats = pat :: pats
          val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1)
          makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
        case (gen: GenFrom) :: test :: rest =>
          val filtered = Apply(orFilter(rhsSelect(gen, nme.withFilter)), makeLambda(gen.pat, test))
          val genFrom =
            if (isIrrefutableGenFrom(gen)) new IrrefutableGenFrom(gen.pat, filtered)
            else GenFrom(gen.pat, filtered)
          makeFor(mapName, flatMapName, genFrom :: rest, body)
        case _ =>
          EmptyTree //may happen for erroneous input
      }
    }

    // begin desugar
    tree match {
      case SymbolLit(str) =>
        Apply(
          ref(defn.SymbolClass.companionModule.termRef),
          Literal(Constant(str)) :: Nil)
      case InterpolatedString(id, segments) =>
        val strs = segments map {
          case ts: Thicket => ts.trees.head
          case t => t
        }
        val elems = segments flatMap {
          case ts: Thicket => ts.trees.tail
          case t => Nil
        }
        Apply(Select(Apply(Ident(nme.StringContext), strs), id), elems)
      case InfixOp(l, op, r) =>
        if (ctx.mode is Mode.Type)
          if (op == tpnme.raw.AMP) AndTypeTree(l, r)     // l & r
          else if (op == tpnme.raw.BAR) OrTypeTree(l, r) // l | r
          else AppliedTypeTree(Ident(op), l :: r :: Nil) // op[l, r]
        else if (ctx.mode is Mode.Pattern)
          Apply(Ident(op), l :: r :: Nil) // op(l, r)
        else // l.op(r), or val x = r; l.op(x), plus handle named args specially
          makeBinop(l, op, r)
      case PostfixOp(t, op) =>
        if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) {
          val seqType = if (ctx.compilationUnit.isJava) defn.ArrayType else defn.SeqType
          Annotated(
            AppliedTypeTree(ref(seqType), t),
            New(ref(defn.RepeatedAnnotType), Nil :: Nil))
        } else {
          assert(ctx.mode.isExpr || ctx.reporter.hasErrors, ctx.mode)
          Select(t, op)
        }
      case PrefixOp(op, t) =>
        Select(t, nme.UNARY_PREFIX ++ op)
      case Parens(t) =>
        t
      case Tuple(ts) =>
        val arity = ts.length
        def tupleTypeRef = defn.TupleType(arity)
        if (arity > Definitions.MaxTupleArity) {
          ctx.error(s"tuple too long (max allowed: ${Definitions.MaxTupleArity})", tree.pos)
          unitLiteral
        } else if (arity == 1) ts.head
        else if (ctx.mode is Mode.Type) AppliedTypeTree(ref(tupleTypeRef), ts)
        else if (arity == 0) unitLiteral
        else Apply(ref(tupleTypeRef.classSymbol.companionModule.valRef), ts)
      case WhileDo(cond, body) =>
        // { <label> def while$(): Unit = if (cond) { body; while$() } ; while$() }
        val call = Apply(Ident(nme.WHILE_PREFIX), Nil)
        val rhs = If(cond, Block(body, call), unitLiteral)
        labelDefAndCall(nme.WHILE_PREFIX, rhs, call)
      case DoWhile(body, cond) =>
        // { label def doWhile$(): Unit = { body; if (cond) doWhile$() } ; doWhile$() }
        val call = Apply(Ident(nme.DO_WHILE_PREFIX), Nil)
        val rhs = Block(body, If(cond, call, unitLiteral))
        labelDefAndCall(nme.DO_WHILE_PREFIX, rhs, call)
      case ForDo(enums, body) =>
        makeFor(nme.foreach, nme.foreach, enums, body) orElse tree
      case ForYield(enums, body) =>
        makeFor(nme.map, nme.flatMap, enums, body) orElse tree
      case PatDef(mods, pats, tpt, rhs) =>
        val pats1 = if (tpt.isEmpty) pats else pats map (Typed(_, tpt))
        flatTree(pats1 map (makePatDef(tree, mods, _, rhs)))
      case ParsedTry(body, handler, finalizer) =>
        handler match {
          case Match(EmptyTree, cases) => Try(body, cases, finalizer)
          case EmptyTree => Try(body, Nil, finalizer)
          case _ =>
            Try(body,
              List(CaseDef(Ident(nme.DEFAULT_EXCEPTION_NAME), EmptyTree, Apply(handler, Ident(nme.DEFAULT_EXCEPTION_NAME)))),
              finalizer)
        }

    }
  }.withPos(tree.pos)

  /** Create a class definition with the same info as the refined type given by `parent`
   *  and `refinements`.
   *
   *      parent { refinements }
   *  ==>
   *      trait <refinement> extends core { this: self => refinements }
   *
   *  Here, `core` is the (possibly parameterized) class part of `parent`.
   *  If `parent` is the same as `core`, self is empty. Otherwise `self` is `parent`.
   *
   *  Example: Given
   *
   *      class C
   *      type T1 = C { type T <: A }
   *
   *  the refined type
   *
   *      T1 { type T <: B }
   *
   *  is expanded to
   *
   *      trait <refinement> extends C { this: T1 => type T <: A }
   *
   *  The result of this method is used for validity checking, is thrown away afterwards.
   *  @param parent  The type of `parent`
   */
  def refinedTypeToClass(parent: tpd.Tree, refinements: List[Tree])(implicit ctx: Context): TypeDef = {
    def stripToCore(tp: Type): List[Type] = tp match {
      case tp: RefinedType if tp.argInfos.nonEmpty => tp :: Nil // parameterized class type
      case tp: TypeRef if tp.symbol.isClass => tp :: Nil     // monomorphic class type
      case tp: TypeProxy => stripToCore(tp.underlying)
      case AndType(tp1, tp2) => stripToCore(tp1) ::: stripToCore(tp2)
      case _ => defn.AnyType :: Nil
    }
    val parentCores = stripToCore(parent.tpe)
    val untpdParent = TypedSplice(parent)
    val (classParents, self) =
      if (parentCores.length == 1 && (parent.tpe eq parentCores.head)) (untpdParent :: Nil, EmptyValDef)
      else (parentCores map TypeTree, ValDef(nme.WILDCARD, untpdParent, EmptyTree))
    val impl = Template(emptyConstructor, classParents, self, refinements)
    TypeDef(tpnme.REFINE_CLASS, impl).withFlags(Trait)
  }

 /** If tree is a variable pattern, return its name and type, otherwise return None.
   */
  private object VarPattern {
    def unapply(tree: Tree)(implicit ctx: Context): Option[VarInfo] = tree match {
      case id: Ident => Some(id, TypeTree())
      case Typed(id: Ident, tpt) => Some((id, tpt))
      case _ => None
    }
  }

  /** Returns list of all pattern variables, possibly with their types,
   *  without duplicates
   */
  private def getVariables(tree: Tree)(implicit ctx: Context): List[VarInfo] = {
    val buf = new ListBuffer[VarInfo]
    def seenName(name: Name) = buf exists (_._1.name == name)
    def add(named: NameTree, t: Tree): Unit =
      if (!seenName(named.name)) buf += ((named, t))
    def collect(tree: Tree): Unit = tree match {
      case Bind(nme.WILDCARD, tree1) =>
        collect(tree1)
      case tree @ Bind(_, Typed(tree1, tpt)) if !mayBeTypePat(tpt) =>
        add(tree, tpt)
        collect(tree1)
      case tree @ Bind(_, tree1) =>
        add(tree, TypeTree())
        collect(tree1)
      case Typed(id: Ident, t) if isVarPattern(id) && id.name != nme.WILDCARD && !isWildcardStarArg(tree) =>
        add(id, t)
      case id: Ident if isVarPattern(id) && id.name != nme.WILDCARD =>
        add(id, TypeTree())
      case Apply(_, args) =>
        args foreach collect
      case Typed(expr, _) =>
        collect(expr)
      case NamedArg(_, arg) =>
        collect(arg)
      case SeqLiteral(elems, _) =>
        elems foreach collect
      case Alternative(trees) =>
        for (tree <- trees; (vble, _) <- getVariables(tree))
          ctx.error("illegal variable in pattern alternative", vble.pos)
      case Annotated(arg, _) =>
        collect(arg)
      case InterpolatedString(_, segments) =>
        segments foreach collect
      case InfixOp(left, _, right) =>
        collect(left)
        collect(right)
      case PrefixOp(_, od) =>
        collect(od)
      case Parens(tree) =>
        collect(tree)
      case Tuple(trees) =>
        trees foreach collect
      case _ =>
    }
    collect(tree)
    buf.toList
  }

  private class IrrefutableGenFrom(pat: Tree, expr: Tree) extends GenFrom(pat, expr)
}