-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Quotes.scala
5292 lines (4226 loc) · 191 KB
/
Quotes.scala
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
package scala.quoted
import scala.annotation.experimental
import scala.annotation.implicitNotFound
import scala.reflect.TypeTest
/** Current Quotes in scope
*
* Usage:
* ```scala
* import scala.quoted.*
* def myExpr[T](using Quotes): Expr[T] = {
* import quotes.reflect.*
* ???
* }
* ```
*/
transparent inline def quotes(using q: Quotes): q.type = q
/** Quotation context provided by a macro expansion or in the scope of `scala.quoted.staging.run`.
* Used to perform all operations on quoted `Expr` or `Type`.
*
* It contains the low-level Typed AST API metaprogramming API.
* This API does not have the static type guarantees that `Expr` and `Type` provide.
* `Quotes` are generated from an enclosing `${ ... }` or `scala.staging.run`. For example:
* ```scala sc:nocompile
* import scala.quoted.*
* inline def myMacro: Expr[T] =
* ${ /* (quotes: Quotes) ?=> */ myExpr }
* def myExpr(using Quotes): Expr[T] =
* '{ f(${ /* (quotes: Quotes) ?=> */ myOtherExpr }) }
* }
* def myOtherExpr(using Quotes): Expr[U] = '{ ... }
* ```
*/
@implicitNotFound("""explain=Maybe this method is missing a `(using Quotes)` parameter.
Maybe that splice `$ { ... }` is missing?
Given instances of `Quotes` are generated from an enclosing splice `$ { ... }` (or `scala.staging.run` call).
A splice can be thought as a method with the following signature.
def $[T](body: Quotes ?=> Expr[T]): T
""")
trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching =>
// Extension methods for `Expr[T]`
extension [T](self: Expr[T])
/** Show a source code like representation of this expression */
def show: String
/** Pattern matches `this` against `that`. Effectively performing a deep equality check.
* It does the equivalent of
* ```scala sc:nocompile
* this match
* case '{...} => true // where the contents of the pattern are the contents of `that`
* case _ => false
* ```
*/
def matches(that: Expr[Any]): Boolean
/** Return the value of this expression.
*
* Returns `None` if the expression does not represent a value or possibly contains side effects.
* Otherwise returns the `Some` of the value.
*/
def value(using FromExpr[T]): Option[T] =
given Quotes = Quotes.this
summon[FromExpr[T]].unapply(self)
/** Return the value of this expression.
*
* Emits an error and throws if the expression does not represent a value or possibly contains side effects.
* Otherwise returns the value.
*/
@deprecated("Use valueOrAbort", "3.1.0")
def valueOrError(using FromExpr[T]): T =
val fromExpr = summon[FromExpr[T]]
def reportError =
val msg = s"Expected a known value. \n\nThe value of: ${self.show}\ncould not be extracted using $fromExpr"
reflect.report.throwError(msg, self)
given Quotes = Quotes.this
fromExpr.unapply(self).getOrElse(reportError)
/** Return the value of this expression.
*
* Emits an error and aborts if the expression does not represent a value or possibly contains side effects.
* Otherwise returns the value.
*/
def valueOrAbort(using FromExpr[T]): T
end extension
// Extension methods for `Expr[Any]` that take another explicit type parameter
extension (self: Expr[Any])
/** Checks is the `quoted.Expr[?]` is valid expression of type `X` */
def isExprOf[X](using Type[X]): Boolean
/** Convert this to an `quoted.Expr[X]` if this expression is a valid expression of type `X` or throws */
def asExprOf[X](using Type[X]): Expr[X]
end extension
/** Low-level Typed AST metaprogramming API.
*
* Provides all functionality related to AST-based metaprogramming.
*
* Usage:
* ```scala
* import scala.quoted.*
* def f(expr: Expr[Int])(using Quotes) =
* import quotes.reflect.*
* val ast: Term = expr.asTerm
* ???
* ```
*
* See `reflectModule` for full API.
*
*/
val reflect: reflectModule
/** Low-level Typed AST metaprogramming API.
*
* Provides all functionality related to AST-based metaprogramming.
*
* Each type `XYZ` in the API is defined as an abstract type `type XYZ`.
* Methods on `XYZ` are provided by a `given XYZMethods` which implements extension methods on `XYZ` in the trait `XYZMethods`.
* The `XYZ` module is defined by a `val XYZ: XYZModule` which contains the methods defined in `XYZModule`.
* Type tests (`TypeTest`) are also given to perform subtype checks on these types.
*
* Type hierarchy
* ```none
*
* +- Tree -+- PackageClause
* |
* +- Statement -+- Import
* | +- Export
* | +- Definition --+- ClassDef
* | | +- TypeDef
* | | +- ValOrDefDef -+- DefDef
* | | +- ValDef
* | |
* | +- Term --------+- Ref -+- Ident -+- Wildcard
* | | +- Select
* | |
* | +- Literal
* | +- This
* | +- New
* | +- NamedArg
* | +- Apply
* | +- TypeApply
* | +- Super
* | +- Assign
* | +- Block
* | +- Closure
* | +- If
* | +- Match
* | +- SummonFrom
* | +- Try
* | +- Return
* | +- Repeated
* | +- Inlined
* | +- SelectOuter
* | +- While
* | +---+- Typed
* | /
* +- TypedOrTest +----------------·
* +- Bind
* +- Unapply
* +- Alternatives
* |
* +- CaseDef
* +- TypeCaseDef
* |
* +- TypeTree ----+- Inferred
* | +- TypeIdent
* | +- TypeSelect
* | +- TypeProjection
* | +- Singleton
* | +- Refined
* | +- Applied
* | +- Annotated
* | +- MatchTypeTree
* | +- ByName
* | +- LambdaTypeTree
* | +- TypeBind
* | +- TypeBlock
* |
* +- TypeBoundsTree
* +- WildcardTypeTree
*
* +- ParamClause -+- TypeParamClause
* +- TermParamClause
*
* +- TypeRepr -+- NamedType -+- TermRef
* | +- TypeRef
* +- ConstantType
* +- SuperType
* +- Refinement
* +- AppliedType
* +- AnnotatedType
* +- AndOrType -+- AndType
* | +- OrType
* +- MatchType
* +- ByNameType
* +- ParamRef
* +- ThisType
* +- RecursiveThis
* +- RecursiveType
* +- LambdaType -+- MethodOrPoly -+- MethodType
* | | +- PolyType
* | +- TypeLambda
* +- MatchCase
* +- TypeBounds
* +- NoPrefix
* +- FlexibleType
*
* +- MethodTypeKind -+- Contextual
* +- Implicit
* +- Plain
*
* +- Selector -+- SimpleSelector
* +- RenameSelector
* +- OmitSelector
* +- GivenSelector
*
* +- Signature
*
* +- Position
*
* +- SourceFile
*
* +- Constant -+- BooleanConstant
* +- ByteConstant
* +- ShortConstant
* +- IntConstant
* +- LongConstant
* +- FloatConstant
* +- DoubleConstant
* +- CharConstant
* +- StringConstant
* +- UnitConstant
* +- NullConstant
* +- ClassOfConstant
* +- Symbol
*
* +- Flags
*
* ```
*
*/
trait reflectModule { self: reflect.type =>
/** Module object of `type CompilationInfo` */
val CompilationInfo: CompilationInfoModule
/** Methods of the module object `val CompilationInfo` */
trait CompilationInfoModule { this: CompilationInfo.type =>
/** Are we expanding a `inline` macro while typing the program?
*
* This will be true when the macro is used in a transparent inline.
*/
def isWhileTyping: Boolean
/** Expose macro-specific settings as a list of strings.
* Settings can be set from command line with help of -Xmacro-settings options.
*
* These will be used to expand any transparent macros or any non-transparent macro that is forced to expand while expanding the transparent macro.
* Non-transparent macros are not guaranteed to be expanded with the same set of settings.
*/
@experimental
def XmacroSettings: List[String]
}
/** Returns the `Term` representation this expression */
extension (expr: Expr[Any])
def asTerm: Term
///////////////
// TREES //
///////////////
/** Tree representing code written in the source */
type Tree <: AnyRef
/** Module object of `type Tree` */
val Tree: TreeModule
/** Methods of the module object `val Tree` */
trait TreeModule { this: Tree.type => }
/** Makes extension methods on `Tree` available without any imports */
given TreeMethods: TreeMethods
/** Extension methods of `Tree` */
trait TreeMethods {
extension (self: Tree)
/** Position in the source code */
def pos: Position
/** Symbol of defined or referred by this tree */
def symbol: Symbol
/** Shows the tree as String */
def show(using Printer[Tree]): String
/** Does this tree represent a valid expression? */
def isExpr: Boolean
/** Convert this tree to an `quoted.Expr[Any]` if the tree is a valid expression or throws */
def asExpr: Expr[Any]
end extension
/** Convert this tree to an `quoted.Expr[T]` if the tree is a valid expression or throws */
extension (self: Tree)
def asExprOf[T](using Type[T]): Expr[T]
extension [ThisTree <: Tree](self: ThisTree)
/** Changes the owner of the symbols in the tree */
def changeOwner(newOwner: Symbol): ThisTree
end extension
}
/** Tree representing a package clause in the source code
*
* ```scala sc:nocompile
* package foo {
* // package stats
* }
* ```
*
* or
*
* ```scala sc:nocompile
* package foo.bar
* // package stats
* ```
*/
type PackageClause <: Tree
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `PackageClause` */
given PackageClauseTypeTest: TypeTest[Tree, PackageClause]
/** Module object of `type PackageClause` */
val PackageClause: PackageClauseModule
/** Methods of the module object `val PackageClause` */
trait PackageClauseModule { this: PackageClause.type =>
/** Create a package clause `package pid { stats }` */
def apply(pid: Ref, stats: List[Tree]): PackageClause
/** Copy a package clause `package pid { stats }` */
def copy(original: Tree)(pid: Ref, stats: List[Tree]): PackageClause
/** Matches a package clause `package pid { stats }` and extracts the `pid` and `stats` */
def unapply(tree: PackageClause): (Ref, List[Tree])
}
/** Makes extension methods on `PackageClause` available without any imports */
given PackageClauseMethods: PackageClauseMethods
/** Extension methods of `PackageClause` */
trait PackageClauseMethods:
extension (self: PackageClause)
/** Tree containing the package name */
def pid: Ref
/** Definitions, imports or exports within the package */
def stats: List[Tree]
end extension
end PackageClauseMethods
/** Tree representing an import in the source code.
*
* See also documentation on `Selector`.
*/
type Import <: Statement
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is an `Import` */
given ImportTypeTest: TypeTest[Tree, Import]
/** Module object of `type Import` */
val Import: ImportModule
/** Methods of the module object `val Import` */
trait ImportModule { this: Import.type =>
/** Create an `Import` with the given qualifier and selectors */
def apply(expr: Term, selectors: List[Selector]): Import
/** Copy an `Import` with the given qualifier and selectors */
def copy(original: Tree)(expr: Term, selectors: List[Selector]): Import
/** Matches an `Import` and extracts the qualifier and selectors */
def unapply(tree: Import): (Term, List[Selector])
}
/** Makes extension methods on `Import` available without any imports */
given ImportMethods: ImportMethods
/** Extension methods of `Import` */
trait ImportMethods:
extension (self: Import)
/** Qualifier of the import */
def expr: Term
/** List selectors of the import
*
* See documentation on `Selector`
*/
def selectors: List[Selector]
end extension
end ImportMethods
/** Tree representing an export clause in the source code.
* Export forwarders generated from this clause appear in the same scope.
*/
type Export <: Statement
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is an `Export` */
given ExportTypeTest: TypeTest[Tree, Export]
/** Module object of `type Export` */
val Export: ExportModule
/** Methods of the module object `val Export` */
trait ExportModule { this: Export.type =>
/** Matches an `Export` and extracts the qualifier and selectors */
def unapply(tree: Export): (Term, List[Selector])
}
/** Makes extension methods on `Export` available without any imports */
given ExportMethods: ExportMethods
/** Extension methods of `Export` */
trait ExportMethods:
extension (self: Export)
/** Qualifier of the export */
def expr: Term
/** List selectors of the export
*
* See documentation on `Selector`
*/
def selectors: List[Selector]
end extension
end ExportMethods
/** Tree representing a statement in the source code */
type Statement <: Tree
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Statement` */
given StatementTypeTest: TypeTest[Tree, Statement]
// ----- Definitions ----------------------------------------------
/** Tree representing a definition in the source code. It can be `ClassDef`, `TypeDef`, `DefDef` or `ValDef` */
type Definition <: Statement
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Definition` */
given DefinitionTypeTest: TypeTest[Tree, Definition]
/** Module object of `type Definition` */
val Definition: DefinitionModule
/** Methods of the module object `val Definition` */
trait DefinitionModule { this: Definition.type => }
/** Makes extension methods on `Definition` available without any imports */
given DefinitionMethods: DefinitionMethods
/** Extension methods of `Definition` */
trait DefinitionMethods:
extension (self: Definition)
/** Name of the definition */
def name: String
end extension
end DefinitionMethods
// ClassDef
/** Tree representing a class definition. This includes anonymous class definitions and the class of a module object */
type ClassDef <: Definition
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `ClassDef` */
given ClassDefTypeTest: TypeTest[Tree, ClassDef]
/** Module object of `type ClassDef` */
val ClassDef: ClassDefModule
/** Methods of the module object `val ClassDef` */
trait ClassDefModule { this: ClassDef.type =>
/** Create a class definition tree
*
* @param cls The class symbol. A new class symbol can be created using `Symbol.newClass`.
* @param parents The parents trees class. The trees must align with the parent types of `cls`.
* Parents can be `TypeTree`s if they don't have term parameter,
* otherwise the can be `Term` containing the `New` applied to the parameters of the extended class.
* @param body List of members of the class. The members must align with the members of `cls`.
*/
// TODO add selfOpt: Option[ValDef]?
@experimental def apply(cls: Symbol, parents: List[Tree /* Term | TypeTree */], body: List[Statement]): ClassDef
def copy(original: Tree)(name: String, constr: DefDef, parents: List[Tree /* Term | TypeTree */], selfOpt: Option[ValDef], body: List[Statement]): ClassDef
def unapply(cdef: ClassDef): (String, DefDef, List[Tree /* Term | TypeTree */], Option[ValDef], List[Statement])
/** Create the ValDef and ClassDef of a module (equivalent to an `object` declaration in source code).
*
* Equivalent to
* ```
* def module(module: Symbol, parents: List[Tree], body: List[Statement]): (ValDef, ClassDef) =
* val modCls = module.moduleClass
* val modClassDef = ClassDef(modCls, parents, body)
* val modValDef = ValDef(module, Some(Apply(Select(New(TypeIdent(modCls)), cls.primaryConstructor), Nil)))
* List(modValDef, modClassDef)
* ```
*
* @param module the module symbol (created using `Symbol.newModule`)
* @param parents parents of the module class
* @param body body of the module class
* @return The module lazy val definition and module class definition.
* These should be added one after the other (in that order) in the body of a class or statements of a block.
*
* @syntax markdown
*/
// TODO add selfOpt: Option[ValDef]?
@experimental def module(module: Symbol, parents: List[Tree /* Term | TypeTree */], body: List[Statement]): (ValDef, ClassDef)
}
/** Makes extension methods on `ClassDef` available without any imports */
given ClassDefMethods: ClassDefMethods
/** Extension methods of `ClassDef` */
trait ClassDefMethods:
extension (self: ClassDef)
/** The primary constructor of this class */
def constructor: DefDef
/** List of extended parent classes or traits.
* The first parent is always a class.
*/
def parents: List[Tree /* Term | TypeTree */]
/** Self-type of the class
*
* ```scala
* //{
* type T
* //}
* class C { self: T =>
* ???
* }
* ```
*/
def self: Option[ValDef]
/** Statements within the class
*
* ```scala
* class C {
* ??? // statements
* }
* ```
*/
def body: List[Statement]
end extension
end ClassDefMethods
// ValOrDefDef
/** Tree representing a value or method definition in the source code.
* This includes `def`, `val`, `lazy val`, `var`, `object` and parameter definitions.
*/
type ValOrDefDef <: Definition
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `ValOrDefDef` */
given ValOrDefDefTypeTest: TypeTest[Tree, ValOrDefDef]
/** Makes extension methods on `ValOrDefDef` available without any imports */
given ValOrDefDefMethods: ValOrDefDefMethods
/** Extension methods of `ValOrDefDef` */
trait ValOrDefDefMethods:
extension (self: ValOrDefDef)
/** The type tree of this `val` or `def` definition */
def tpt: TypeTree
/** The right-hand side of this `val` or `def` definition */
def rhs: Option[Term]
end extension
end ValOrDefDefMethods
// DefDef
/** Tree representing a method definition in the source code */
type DefDef <: ValOrDefDef
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `DefDef` */
given DefDefTypeTest: TypeTest[Tree, DefDef]
/** Module object of `type DefDef` */
val DefDef: DefDefModule
/** Methods of the module object `val DefDef` */
trait DefDefModule { this: DefDef.type =>
/** Create a method definition `def f[..](...)` with the signature defined in the symbol.
*
* The `rhsFn` is a function that receives references to its parameters, and should return
* `Some` containing the implementation of the method, or `None` if the method has no implementation.
* Any definition directly inside the implementation should have `symbol` as owner.
*
* Use `Symbol.asQuotes` to create the rhs using quoted code.
*
* See also: `Tree.changeOwner`
*/
def apply(symbol: Symbol, rhsFn: List[List[Tree]] => Option[Term]): DefDef
def copy(original: Tree)(name: String, paramss: List[ParamClause], tpt: TypeTree, rhs: Option[Term]): DefDef
def unapply(ddef: DefDef): (String, List[ParamClause], TypeTree, Option[Term])
}
/** Makes extension methods on `DefDef` available without any imports */
given DefDefMethods: DefDefMethods
/** Extension methods of `DefDef` */
trait DefDefMethods:
extension (self: DefDef)
/** List of type and term parameter clauses */
def paramss: List[ParamClause]
/** List of leading type parameters or Nil if the method does not have leading type parameters.
*
* Note: Non leading type parameters can be found in extension methods such as
* ```scala
* //{
* type A
* type T
* //}
* extension (a: A) def f[T]() = ???
* ```
*/
def leadingTypeParams: List[TypeDef]
/** List of parameter clauses following the leading type parameters or all clauses.
* Return all parameter clauses if there are no leading type parameters.
*
* Non leading type parameters can be found in extension methods such as
* ```scala
* //{
* type T
* type A
* //}
* extension (a: A) def f[T]() = ???
* ```
*/
def trailingParamss: List[ParamClause]
/** List of term parameter clauses */
def termParamss: List[TermParamClause]
/** The tree of the return type of this `def` definition */
def returnTpt: TypeTree
/** The tree of the implementation of the method.
* Returns `None` if the method does not have an implementation.
*/
def rhs: Option[Term]
end extension
end DefDefMethods
// ValDef
/** Tree representing a value definition in the source code. This includes `val`, `lazy val`, `var`, `object` and parameter definitions. */
type ValDef <: ValOrDefDef
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `ValDef` */
given ValDefTypeTest: TypeTest[Tree, ValDef]
/** Module object of `type ValDef` */
val ValDef: ValDefModule
/** Methods of the module object `val ValDef` */
trait ValDefModule { this: ValDef.type =>
/** Create a value definition `val x`, `var x` or `lazy val x` with the signature defined in the symbol.
*
* The `rhs` should return `Some` containing the implementation of the method,
* or `None` if the method has no implementation.
* Any definition directly inside the implementation should have `symbol` as owner.
*
* Use `Symbol.asQuotes` to create the rhs using quoted code.
*
* See also: `Tree.changeOwner`
*/
def apply(symbol: Symbol, rhs: Option[Term]): ValDef
def copy(original: Tree)(name: String, tpt: TypeTree, rhs: Option[Term]): ValDef
def unapply(vdef: ValDef): (String, TypeTree, Option[Term])
/** Creates a block `{ val <name> = <rhs: Term>; <body(x): Term> }`
*
* Usage:
* ```
* ValDef.let(owner, "x", rhs1) { x =>
* ValDef.let(x.symbol.owner, "y", rhs2) { y =>
* // use `x` and `y`
* }
* }
* ```
*/
def let(owner: Symbol, name: String, rhs: Term)(body: Ref => Term): Term
/** Creates a block `{ val x = <rhs: Term>; <body(x): Term> }`
*
* Usage:
* ```
* ValDef.let(owner, rhs1) { x =>
* ValDef.let(owner, rhs2) { y =>
* // use `x` and `y`
* }
* }
* ```
*/
def let(owner: Symbol, rhs: Term)(body: Ref => Term): Term =
let(owner, "x", rhs)(body)
/** Creates a block `{ val x1 = <terms(0): Term>; ...; val xn = <terms(n-1): Term>; <body(List(x1, ..., xn)): Term> }`
*
* Usage:
* ```
* ValDef.let(owner, rhsList) { xs =>
* ...
* }
* ```
*/
def let(owner: Symbol, terms: List[Term])(body: List[Ref] => Term): Term
}
/** Makes extension methods on `ValDef` available without any imports */
given ValDefMethods: ValDefMethods
/** Extension methods of `ValDef` */
trait ValDefMethods:
extension (self: ValDef)
/** The type tree of this `val` definition */
def tpt: TypeTree
/** The right-hand side of this `val` definition */
def rhs: Option[Term]
end extension
end ValDefMethods
// TypeDef
/** Tree representing a type (parameter or member) definition in the source code */
type TypeDef <: Definition
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `TypeDef` */
given TypeDefTypeTest: TypeTest[Tree, TypeDef]
/** Module object of `type TypeDef` */
val TypeDef: TypeDefModule
/** Methods of the module object `val TypeDef` */
trait TypeDefModule { this: TypeDef.type =>
def apply(symbol: Symbol): TypeDef
def copy(original: Tree)(name: String, rhs: Tree): TypeDef
def unapply(tdef: TypeDef): (String, Tree)
}
/** Makes extension methods on `TypeDef` available without any imports */
given TypeDefMethods: TypeDefMethods
/** Extension methods of `TypeDef` */
trait TypeDefMethods:
extension (self: TypeDef)
/** The type bounds on the right-hand side of this `type` definition */
def rhs: Tree
end extension
end TypeDefMethods
// ----- Terms ----------------------------------------------------
/** Tree representing an expression in the source code */
type Term <: Statement
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Term` */
given TermTypeTest: TypeTest[Tree, Term]
/** Module object of `type Term` */
val Term: TermModule
/** Methods of the module object `val Term` */
trait TermModule { this: Term.type =>
/** Returns a term that is functionally equivalent to `t`,
* however if `t` is of the form `((y1, ..., yn) => e2)(e1, ..., en)`
* then it optimizes the top most call by returning `Some`
* with the result of beta-reducing the function application.
* Similarly, all outermost curried function applications will be beta-reduced, if possible.
* Otherwise returns `None`.
*
* To retain semantics the argument `ei` is bound as `val yi = ei` and by-name arguments to `def yi = ei`.
* Some bindings may be elided as an early optimization.
*
* Example:
* ```scala sc:nocompile
* ((a: Int, b: Int) => a + b).apply(x, y)
* ```
* will be reduced to
* ```scala sc:nocompile
* val a = x
* val b = y
* a + b
* ```
*
* Generally:
* ```scala sc:nocompile
* ([X1, Y1, ...] => (x1, y1, ...) => ... => [Xn, Yn, ...] => (xn, yn, ...) => f[X1, Y1, ..., Xn, Yn, ...](x1, y1, ..., xn, yn, ...))).apply[Tx1, Ty1, ...](myX1, myY1, ...)....apply[Txn, Tyn, ...](myXn, myYn, ...)
* ```
* will be reduced to
* ```scala sc:nocompile
* type X1 = Tx1
* type Y1 = Ty1
* ...
* val x1 = myX1
* val y1 = myY1
* ...
* type Xn = Txn
* type Yn = Tyn
* ...
* val xn = myXn
* val yn = myYn
* ...
* f[X1, Y1, ..., Xn, Yn, ...](x1, y1, ..., xn, yn, ...)
* ```
*/
def betaReduce(term: Term): Option[Term]
}
/** Makes extension methods on `Term` available without any imports */
given TermMethods: TermMethods
/** Extension methods of `Term` */
trait TermMethods {
extension (self: Term)
/** TypeRepr of this term */
def tpe: TypeRepr
/** Replace Inlined nodes and InlineProxy references to underlying arguments.
* The resulting tree is useful for inspection of the value or content of a non-inline argument.
*
* Warning: This tree may contain references that are out of scope and should not be used in the generated code.
* This method should only used to port Scala 2 that used to access their outer scope unsoundly.
*/
def underlyingArgument: Term
/** Replace Ident nodes references to the underlying tree that defined them.
* The resulting tree is useful for inspection of the definition of some bindings.
*
* Warning: This tree may contain references that are out of scope and should not be used in the generated code.
* This method should only used to port Scala 2 that used to access their outer scope unsoundly.
*/
def underlying: Term
/** Converts a partially applied term into a lambda expression */
def etaExpand(owner: Symbol): Term
/** A unary apply node with given argument: `tree(arg)` */
def appliedTo(arg: Term): Term
/** An apply node with given arguments: `tree(arg, args0, ..., argsN)` */
def appliedTo(arg: Term, args: Term*): Term
/** An apply node with given argument list `tree(args(0), ..., args(args.length - 1))` */
def appliedToArgs(args: List[Term]): Apply
/** The current tree applied to given argument lists:
* `tree (argss(0)) ... (argss(argss.length -1))`
*/
def appliedToArgss(argss: List[List[Term]]): Term
/** The current tree applied to (): `tree()` */
def appliedToNone: Apply
/** The current tree applied to given type argument: `tree[targ]` */
def appliedToType(targ: TypeRepr): Term
/** The current tree applied to given type arguments: `tree[targ0, ..., targN]` */
def appliedToTypes(targs: List[TypeRepr]): Term
/** The current tree applied to given type argument list: `tree[targs(0), ..., targs(targs.length - 1)]` */
def appliedToTypeTrees(targs: List[TypeTree]): Term
/** A select node that selects the given symbol. */
def select(sym: Symbol): Select
end extension
}
/** Tree representing a reference to definition */
type Ref <: Term
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Ref` */
given RefTypeTest: TypeTest[Tree, Ref]
/** Module object of `type Ref` */
val Ref: RefModule
/** Methods of the module object `val Ref` */
trait RefModule { this: Ref.type =>
/** A tree representing the same reference as the given type */
def term(tp: TermRef): Ref
/** Create a reference tree from a symbol
*
* If `sym` refers to a class member `foo` in class `C`,
* returns a tree representing `C.this.foo`.
*
* If `sym` refers to a local definition `foo`, returns
* a tree representing `foo`.
*
* @note In both cases, the constructed tree should only
* be spliced into the places where such accesses make sense.
* For example, it is incorrect to have `C.this.foo` outside
* the class body of `C`, or have `foo` outside the lexical
* scope for the definition of `foo`.
*/
def apply(sym: Symbol): Ref
}
/** Tree representing a reference to definition with a given name */
type Ident <: Ref
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is an `Ident` */
given IdentTypeTest: TypeTest[Tree, Ident]
/** Module object of `type Ident` */
val Ident: IdentModule
/** Methods of the module object `val Ident` */
trait IdentModule { this: Ident.type =>
def apply(tmref: TermRef): Term
def copy(original: Tree)(name: String): Ident
/** Matches a term identifier and returns its name */
def unapply(tree: Ident): Some[String]
}
/** Makes extension methods on `Ident` available without any imports */
given IdentMethods: IdentMethods
/** Extension methods of `Ident` */
trait IdentMethods:
extension (self: Ident)
/** Name of this `Ident` */
def name: String
end extension
end IdentMethods
/** Pattern representing a `_` wildcard. */
type Wildcard <: Ident
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Wildcard` */
given WildcardTypeTest: TypeTest[Tree, Wildcard]
/** Module object of `type Wildcard` */
val Wildcard: WildcardModule
/** Methods of the module object `val Wildcard` */
trait WildcardModule { this: Wildcard.type =>
/** Create a tree representing a `_` wildcard. */
def apply(): Wildcard
/** Match a tree representing a `_` wildcard. */
def unapply(wildcard: Wildcard): true
}
/** Tree representing a selection of definition with a given name on a given prefix */
type Select <: Ref
/** `TypeTest` that allows testing at runtime in a pattern match if a `Tree` is a `Select` */
given SelectTypeTest: TypeTest[Tree, Select]
/** Module object of `type Select` */
val Select: SelectModule
/** Methods of the module object `val Select` */
trait SelectModule { this: Select.type =>
/** Select a term member by symbol */
def apply(qualifier: Term, symbol: Symbol): Select
/** Select a field or a non-overloaded method by name
*
* @note The method will produce an assertion error if the selected
* method is overloaded. The method `overloaded` should be used
* in that case.
*/
def unique(qualifier: Term, name: String): Select
/** Call an overloaded method with the given type and term parameters */
def overloaded(qualifier: Term, name: String, targs: List[TypeRepr], args: List[Term]): Term
/** Call an overloaded method with the given type and term parameters */
def overloaded(qualifier: Term, name: String, targs: List[TypeRepr], args: List[Term], returnType: TypeRepr): Term
def copy(original: Tree)(qualifier: Term, name: String): Select
/** Matches `<qualifier: Term>.<name: String>` */
def unapply(x: Select): (Term, String)