forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 17
/
Types.scala
4016 lines (3440 loc) · 156 KB
/
Types.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 dotty.tools
package dotc
package core
import util.common._
import Symbols._
import Flags._
import Names._
import StdNames._, NameOps._
import NameKinds.{ShadowedName, SkolemName}
import Scopes._
import Constants._
import Contexts._
import Annotations._
import SymDenotations._
import Decorators._
import Denotations._
import Periods._
import util.Positions.{Position, NoPosition}
import util.Stats._
import util.{DotClass, SimpleMap}
import reporting.diagnostic.Message
import reporting.diagnostic.messages.CyclicReferenceInvolving
import ast.tpd._
import ast.TreeTypeMap
import printing.Texts._
import ast.untpd
import dotty.tools.dotc.transform.Erasure
import printing.Printer
import Hashable._
import Uniques._
import collection.{mutable, Seq, breakOut}
import config.Config
import annotation.tailrec
import Flags.FlagSet
import language.implicitConversions
import scala.util.hashing.{ MurmurHash3 => hashing }
import config.Printers.{core, typr, cyclicErrors}
object Types {
@sharable private var nextId = 0
/** Main class representing types.
*
* The principal subclasses and sub-objects are as follows:
*
* ```none
* Type -+- ProxyType --+- NamedType ----+--- TypeRef
* | | \
* | +- SingletonType-+-+- TermRef
* | | |
* | | +--- ThisType
* | | +--- SuperType
* | | +--- ConstantType
* | | +--- TermParamRef
* | | +----RecThis
* | | +--- SkolemType
* | +- TypeParamRef
* | +- RefinedOrRecType -+-- RefinedType
* | | -+-- RecType
* | +- HKApply
* | +- TypeBounds
* | +- ExprType
* | +- AnnotatedType
* | +- TypeVar
* | +- HKTypeLambda
* |
* +- GroundType -+- AndType
* +- OrType
* +- MethodOrPoly ---+-- PolyType
* +-- MethodType ---+- ImplicitMethodType
* | +- JavaMethodType
* +- ClassInfo
* |
* +- NoType
* +- NoPrefix
* +- ErrorType
* +- WildcardType
* ```
*
* Note: please keep in sync with copy in `docs/docs/internals/type-system.md`.
*/
abstract class Type extends DotClass with Hashable with printing.Showable {
// ----- Tests -----------------------------------------------------
// debug only: a unique identifier for a type
val uniqId = {
nextId = nextId + 1
// if (nextId == 19555)
// println("foo")
nextId
}
/** Is this type different from NoType? */
def exists: Boolean = true
/** This type, if it exists, otherwise `that` type */
def orElse(that: => Type) = if (exists) this else that
/** Is this type a value type? */
final def isValueType: Boolean = this.isInstanceOf[ValueType]
/** Is the is value type or type lambda? */
final def isValueTypeOrLambda: Boolean = isValueType || this.isInstanceOf[TypeLambda]
/** Does this type denote a stable reference (i.e. singleton type)? */
final def isStable(implicit ctx: Context): Boolean = stripTypeVar match {
case tp: TermRef => tp.termSymbol.isStable && tp.prefix.isStable || tp.info.isStable
case _: SingletonType | NoPrefix => true
case tp: RefinedOrRecType => tp.parent.isStable
case tp: ExprType => tp.resultType.isStable
case _ => false
}
/** Is this type a (possibly refined or applied or aliased) type reference
* to the given type symbol?
* @sym The symbol to compare to. It must be a class symbol or abstract type.
* It makes no sense for it to be an alias type because isRef would always
* return false in that case.
*/
def isRef(sym: Symbol)(implicit ctx: Context): Boolean = stripAnnots.stripTypeVar match {
case this1: TypeRef =>
this1.info match { // see comment in Namer#typeDefSig
case TypeAlias(tp) => tp.isRef(sym)
case _ => this1.symbol eq sym
}
case this1: RefinedOrRecType => this1.parent.isRef(sym)
case this1: HKApply => this1.superType.isRef(sym)
case _ => false
}
/** Is this type a (neither aliased nor applied) reference to class `sym`? */
def isDirectRef(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match {
case this1: TypeRef =>
this1.name == sym.name && // avoid forcing info if names differ
(this1.symbol eq sym)
case _ =>
false
}
/** Does this type refer exactly to class symbol `sym`, instead of to a subclass of `sym`?
* Implemented like `isRef`, but follows more types: all type proxies as well as and- and or-types
*/
private[Types] def isTightPrefix(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match {
case tp: NamedType => tp.info.isTightPrefix(sym)
case tp: ClassInfo => tp.cls eq sym
case tp: Types.ThisType => tp.cls eq sym
case tp: TypeProxy => tp.underlying.isTightPrefix(sym)
case tp: AndType => tp.tp1.isTightPrefix(sym) && tp.tp2.isTightPrefix(sym)
case tp: OrType => tp.tp1.isTightPrefix(sym) || tp.tp2.isTightPrefix(sym)
case _ => false
}
/** Is this type an instance of a non-bottom subclass of the given class `cls`? */
final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = {
def loop(tp: Type): Boolean = tp match {
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass) sym.derivesFrom(cls) else loop(tp.superType): @tailrec
case tp: TypeProxy =>
loop(tp.underlying): @tailrec
case tp: AndType =>
loop(tp.tp1) || loop(tp.tp2): @tailrec
case tp: OrType =>
loop(tp.tp1) && loop(tp.tp2): @tailrec
case tp: JavaArrayType =>
cls == defn.ObjectClass
case _ =>
false
}
cls == defn.AnyClass || loop(this)
}
/** Is this type guaranteed not to have `null` as a value?
* For the moment this is only true for modules, but it could
* be refined later.
*/
final def isNotNull(implicit ctx: Context): Boolean =
classSymbol is ModuleClass
/** Is this type produced as a repair for an error? */
final def isError(implicit ctx: Context): Boolean = stripTypeVar match {
case _: ErrorType => true
case tp => (tp.typeSymbol is Erroneous) || (tp.termSymbol is Erroneous)
}
/** Is some part of this type produced as a repair for an error? */
final def isErroneous(implicit ctx: Context): Boolean = existsPart(_.isError, forceLazy = false)
/** Does the type carry an annotation that is an instance of `cls`? */
@tailrec final def hasAnnotation(cls: ClassSymbol)(implicit ctx: Context): Boolean = stripTypeVar match {
case AnnotatedType(tp, annot) => (annot matches cls) || (tp hasAnnotation cls)
case _ => false
}
/** Does this type occur as a part of type `that`? */
final def occursIn(that: Type)(implicit ctx: Context): Boolean =
that existsPart (this == _)
/** Is this a type of a repeated parameter? */
def isRepeatedParam(implicit ctx: Context): Boolean =
typeSymbol eq defn.RepeatedParamClass
/** Does this type carry an UnsafeNonvariant annotation? */
final def isUnsafeNonvariant(implicit ctx: Context): Boolean = this match {
case AnnotatedType(_, annot) => annot.symbol == defn.UnsafeNonvariantAnnot
case _ => false
}
/** Does this type have an UnsafeNonvariant annotation on one of its parts? */
final def hasUnsafeNonvariant(implicit ctx: Context): Boolean =
new HasUnsafeNonAccumulator().apply(false, this)
/** Is this the type of a method that has a repeated parameter type as
* last parameter type?
*/
def isVarArgsMethod(implicit ctx: Context): Boolean = stripPoly match {
case mt: MethodType => mt.paramInfos.nonEmpty && mt.paramInfos.last.isRepeatedParam
case _ => false
}
/** Is this the type of a method with a leading empty parameter list?
*/
def isNullaryMethod(implicit ctx: Context): Boolean = stripPoly match {
case MethodType(Nil) => true
case _ => false
}
/** Is this an alias TypeBounds? */
def isAlias: Boolean = this.isInstanceOf[TypeAlias]
// ----- Higher-order combinators -----------------------------------
/** Returns true if there is a part of this type that satisfies predicate `p`.
*/
final def existsPart(p: Type => Boolean, forceLazy: Boolean = true)(implicit ctx: Context): Boolean =
new ExistsAccumulator(p, forceLazy).apply(false, this)
/** Returns true if all parts of this type satisfy predicate `p`.
*/
final def forallParts(p: Type => Boolean)(implicit ctx: Context): Boolean =
!existsPart(!p(_))
/** Performs operation on all parts of this type */
final def foreachPart(p: Type => Unit, stopAtStatic: Boolean = false)(implicit ctx: Context): Unit =
new ForeachAccumulator(p, stopAtStatic).apply((), this)
/** The parts of this type which are type or term refs */
final def namedParts(implicit ctx: Context): collection.Set[NamedType] =
namedPartsWith(alwaysTrue)
/** The parts of this type which are type or term refs and which
* satisfy predicate `p`.
*
* @param p The predicate to satisfy
* @param excludeLowerBounds If set to true, the lower bounds of abstract
* types will be ignored.
*/
def namedPartsWith(p: NamedType => Boolean, excludeLowerBounds: Boolean = false)
(implicit ctx: Context): collection.Set[NamedType] =
new NamedPartsAccumulator(p, excludeLowerBounds).apply(mutable.LinkedHashSet(), this)
/** Map function `f` over elements of an AndType, rebuilding with function `g` */
def mapReduceAnd[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar match {
case AndType(tp1, tp2) => g(tp1.mapReduceAnd(f)(g), tp2.mapReduceAnd(f)(g))
case _ => f(this)
}
/** Map function `f` over elements of an OrType, rebuilding with function `g` */
final def mapReduceOr[T](f: Type => T)(g: (T, T) => T)(implicit ctx: Context): T = stripTypeVar match {
case OrType(tp1, tp2) => g(tp1.mapReduceOr(f)(g), tp2.mapReduceOr(f)(g))
case _ => f(this)
}
// ----- Associated symbols ----------------------------------------------
/** The type symbol associated with the type */
@tailrec final def typeSymbol(implicit ctx: Context): Symbol = this match {
case tp: TypeRef => tp.symbol
case tp: ClassInfo => tp.cls
// case ThisType(cls) => cls // needed?
case tp: SingletonType => NoSymbol
case tp: TypeProxy => tp.underlying.typeSymbol
case _ => NoSymbol
}
/** The least class or trait of which this type is a subtype or parameterized
* instance, or NoSymbol if none exists (either because this type is not a
* value type, or because superclasses are ambiguous).
*/
final def classSymbol(implicit ctx: Context): Symbol = this match {
case ConstantType(constant) =>
constant.tpe.classSymbol: @tailrec
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass) sym else tp.superType.classSymbol: @tailrec
case tp: ClassInfo =>
tp.cls
case tp: SingletonType =>
NoSymbol
case tp: TypeProxy =>
tp.underlying.classSymbol: @tailrec
case AndType(l, r) =>
val lsym = l.classSymbol
val rsym = r.classSymbol
if (lsym isSubClass rsym) lsym
else if (rsym isSubClass lsym) rsym
else NoSymbol
case OrType(l, r) => // TODO does not conform to spec
val lsym = l.classSymbol
val rsym = r.classSymbol
if (lsym isSubClass rsym) rsym
else if (rsym isSubClass lsym) lsym
else NoSymbol
case _ =>
NoSymbol
}
/** The least (wrt <:<) set of class symbols of which this type is a subtype
*/
final def classSymbols(implicit ctx: Context): List[ClassSymbol] = this match {
case tp: ClassInfo =>
tp.cls :: Nil
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass) sym.asClass :: Nil else tp.superType.classSymbols: @tailrec
case tp: TypeProxy =>
tp.underlying.classSymbols: @tailrec
case AndType(l, r) =>
l.classSymbols union r.classSymbols
case OrType(l, r) =>
l.classSymbols intersect r.classSymbols // TODO does not conform to spec
case _ =>
Nil
}
/** The term symbol associated with the type */
@tailrec final def termSymbol(implicit ctx: Context): Symbol = this match {
case tp: TermRef => tp.symbol
case tp: TypeProxy => tp.underlying.termSymbol
case _ => NoSymbol
}
/** The base classes of this type as determined by ClassDenotation
* in linearization order, with the class itself as first element.
* For AndTypes/OrTypes, the union/intersection of the operands' baseclasses.
* Inherited by all type proxies. `Nil` for all other types.
*/
final def baseClasses(implicit ctx: Context): List[ClassSymbol] = track("baseClasses") {
this match {
case tp: TypeProxy =>
tp.underlying.baseClasses
case tp: ClassInfo =>
tp.cls.baseClasses
case AndType(tp1, tp2) =>
tp1.baseClasses union tp2.baseClasses
case OrType(tp1, tp2) =>
tp1.baseClasses intersect tp2.baseClasses
case _ => Nil
}
}
// ----- Member access -------------------------------------------------
/** The scope of all declarations of this type.
* Defined by ClassInfo, inherited by type proxies.
* Empty scope for all other types.
*/
@tailrec final def decls(implicit ctx: Context): Scope = this match {
case tp: ClassInfo =>
tp.decls
case tp: TypeProxy =>
tp.underlying.decls: @tailrec
case _ =>
EmptyScope
}
/** A denotation containing the declaration(s) in this type with the given name.
* The result is either a SymDenotation or a MultiDenotation of SymDenotations.
* The info(s) are the original symbol infos, no translation takes place.
*/
final def decl(name: Name)(implicit ctx: Context): Denotation = track("decl") {
findDecl(name, EmptyFlags)
}
/** A denotation containing the non-private declaration(s) in this type with the given name */
final def nonPrivateDecl(name: Name)(implicit ctx: Context): Denotation = track("nonPrivateDecl") {
findDecl(name, Private)
}
/** A denotation containing the declaration(s) in this type with the given
* name, as seen from prefix type `pre`. Declarations that have a flag
* in `excluded` are omitted.
*/
@tailrec final def findDecl(name: Name, excluded: FlagSet)(implicit ctx: Context): Denotation = this match {
case tp: ClassInfo =>
tp.decls.denotsNamed(name).filterExcluded(excluded).toDenot(NoPrefix)
case tp: TypeProxy =>
tp.underlying.findDecl(name, excluded)
case err: ErrorType =>
ctx.newErrorSymbol(classSymbol orElse defn.RootClass, name, err.msg)
case _ =>
NoDenotation
}
/** The member of this type with the given name */
final def member(name: Name)(implicit ctx: Context): Denotation = /*>|>*/ track("member") /*<|<*/ {
memberExcluding(name, EmptyFlags)
}
/** The non-private member of this type with the given name. */
final def nonPrivateMember(name: Name)(implicit ctx: Context): Denotation = track("nonPrivateMember") {
memberExcluding(name, Flags.Private)
}
final def memberExcluding(name: Name, excluding: FlagSet)(implicit ctx: Context): Denotation = {
// We need a valid prefix for `asSeenFrom`
val pre = this match {
case tp: ClassInfo =>
tp.typeRef
case _ =>
widenIfUnstable
}
findMember(name, pre, excluding)
}
/** Find member of this type with given name and
* produce a denotation that contains the type of the member
* as seen from given prefix `pre`. Exclude all members that have
* flags in `excluded` from consideration.
*/
final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = {
@tailrec def go(tp: Type): Denotation = tp match {
case tp: RefinedType =>
if (name eq tp.refinedName) goRefined(tp) else go(tp.parent)
case tp: ThisType =>
goThis(tp)
case tp: TypeRef =>
tp.denot.findMember(name, pre, excluded)
case tp: TermRef =>
go (tp.underlying match {
case mt: MethodType
if mt.paramInfos.isEmpty && (tp.symbol is Stable) => mt.resultType
case tp1 => tp1
})
case tp: TypeParamRef =>
goParam(tp)
case tp: RecType =>
goRec(tp)
case tp: HKApply =>
goApply(tp)
case tp: TypeProxy =>
go(tp.underlying)
case tp: ClassInfo =>
tp.cls.findMember(name, pre, excluded)
case AndType(l, r) =>
goAnd(l, r)
case tp: OrType =>
// we need to keep the invariant that `pre <: tp`. Branch `union-types-narrow-prefix`
// achieved that by narrowing `pre` to each alternative, but it led to merge errors in
// lots of places. The present strategy is instead of widen `tp` using `join` to be a
// supertype of `pre`.
go(tp.join)
case tp: JavaArrayType =>
defn.ObjectType.findMember(name, pre, excluded)
case err: ErrorType =>
ctx.newErrorSymbol(pre.classSymbol orElse defn.RootClass, name, err.msg)
case _ =>
NoDenotation
}
def goRec(tp: RecType) =
if (tp.parent == null) NoDenotation
else {
//println(s"find member $pre . $name in $tp")
// We have to be careful because we might open the same (wrt eq) recursive type
// twice during findMember which risks picking the wrong prefix in the `substRecThis(rt, pre)`
// call below. To avoid this problem we do a defensive copy of the recursive
// type first. But if we do this always we risk being inefficient and we ran into
// stackoverflows when compiling pos/hk.scala under the refinement encoding
// of hk-types. So we only do a copy if the type
// is visited again in a recursive call to `findMember`, as tracked by `tp.opened`.
// Furthermore, if this happens we mark the original recursive type with `openedTwice`
// which means that we always defensively copy the type in the future. This second
// measure is necessary because findMember calls might be cached, so do not
// necessarily appear in nested order.
// Without the defensive copy, Typer.scala fails to compile at the line
//
// untpd.rename(lhsCore, setterName).withType(setterType), WildcardType)
//
// because the subtype check
//
// ThisTree[Untyped]#ThisTree[Typed] <: Tree[Typed]
//
// fails (in fact it thinks the underlying type of the LHS is `Tree[Untyped]`.)
//
// Without the `openedTwice` trick, Typer.scala fails to Ycheck
// at phase resolveSuper.
val rt =
if (tp.opened) { // defensive copy
tp.openedTwice = true
RecType(rt => tp.parent.substRecThis(tp, RecThis(rt)))
} else tp
rt.opened = true
try go(rt.parent).mapInfo(_.substRecThis(rt, pre))
finally {
if (!rt.openedTwice) rt.opened = false
}
}
def goRefined(tp: RefinedType) = {
val pdenot = go(tp.parent)
val rinfo = tp.refinedInfo
if (name.isTypeName) { // simplified case that runs more efficiently
val jointInfo =
if (rinfo.isAlias) rinfo
else if (pdenot.info.isAlias) pdenot.info
else if (ctx.pendingMemberSearches.contains(name)) pdenot.info safe_& rinfo
else
try pdenot.info & rinfo
catch {
case ex: CyclicReference =>
// happens for tests/pos/sets.scala. findMember is called from baseTypeRef.
// The & causes a subtype check which calls baseTypeRef again with the same
// superclass. In the observed case, the superclass was Any, and
// the special shortcut for Any in derivesFrom was as yet absent. To reproduce,
// remove the special treatment of Any in derivesFrom and compile
// sets.scala.
pdenot.info safe_& rinfo
}
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo)
} else {
pdenot & (
new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId)),
pre,
safeIntersection = ctx.pendingMemberSearches.contains(name))
}
}
def goApply(tp: HKApply) = tp.tycon match {
case tl: HKTypeLambda =>
go(tl.resType).mapInfo(info =>
tl.derivedLambdaAbstraction(tl.paramNames, tl.paramInfos, info).appliedTo(tp.args))
case _ =>
go(tp.superType)
}
def goThis(tp: ThisType) = {
val d = go(tp.underlying)
if (d.exists) d
else
// There is a special case to handle:
// trait Super { this: Sub => private class Inner {} println(this.Inner) }
// class Sub extends Super
// When resolving Super.this.Inner, the normal logic goes to the self type and
// looks for Inner from there. But this fails because Inner is private.
// We fix the problem by having the following fallback case, which links up the
// member in Super instead of Sub.
// As an example of this in the wild, see
// loadClassWithPrivateInnerAndSubSelf in ShowClassTests
go(tp.cls.typeRef) orElse d
}
def goParam(tp: TypeParamRef) = {
val next = tp.underlying
ctx.typerState.constraint.entry(tp) match {
case bounds: TypeBounds if bounds ne next =>
ctx.typerState.ephemeral = true
go(bounds.hi)
case _ =>
go(next)
}
}
def goAnd(l: Type, r: Type) = {
go(l) & (go(r), pre, safeIntersection = ctx.pendingMemberSearches.contains(name))
}
{ val recCount = ctx.findMemberCount + 1
ctx.findMemberCount = recCount
if (recCount >= Config.LogPendingFindMemberThreshold) {
ctx.pendingMemberSearches = name :: ctx.pendingMemberSearches
if (ctx.property(TypeOps.findMemberLimit).isDefined &&
ctx.findMemberCount > Config.PendingFindMemberLimit)
return NoDenotation
}
}
//assert(ctx.findMemberCount < 20)
try go(this)
catch {
case ex: Throwable =>
core.println(i"findMember exception for $this member $name, pre = $pre")
throw ex // DEBUG
}
finally {
val recCount = ctx.findMemberCount
if (recCount >= Config.LogPendingFindMemberThreshold)
ctx.pendingMemberSearches = ctx.pendingMemberSearches.tail
ctx.findMemberCount = recCount - 1
}
}
/** The set of names of members of this type that pass the given name filter
* when seen as members of `pre`. More precisely, these are all
* of members `name` such that `keepOnly(pre, name)` is `true`.
* @note: OK to use a Set[Name] here because Name hashcodes are replayable,
* hence the Set will always give the same names in the same order.
*/
final def memberNames(keepOnly: NameFilter, pre: Type = this)(implicit ctx: Context): Set[Name] = this match {
case tp: ClassInfo =>
tp.cls.memberNames(keepOnly) filter (keepOnly(pre, _))
case tp: RefinedType =>
val ns = tp.parent.memberNames(keepOnly, pre)
if (keepOnly(pre, tp.refinedName)) ns + tp.refinedName else ns
case tp: TypeProxy =>
tp.underlying.memberNames(keepOnly, pre): @tailrec
case tp: AndType =>
tp.tp1.memberNames(keepOnly, pre) | tp.tp2.memberNames(keepOnly, pre)
case tp: OrType =>
tp.tp1.memberNames(keepOnly, pre) & tp.tp2.memberNames(keepOnly, pre)
case _ =>
Set()
}
def memberDenots(keepOnly: NameFilter, f: (Name, mutable.Buffer[SingleDenotation]) => Unit)(implicit ctx: Context): Seq[SingleDenotation] = {
val buf = mutable.ArrayBuffer[SingleDenotation]()
for (name <- memberNames(keepOnly)) f(name, buf)
buf
}
/** The set of abstract term members of this type. */
final def abstractTermMembers(implicit ctx: Context): Seq[SingleDenotation] = track("abstractTermMembers") {
memberDenots(abstractTermNameFilter,
(name, buf) => buf ++= nonPrivateMember(name).altsWith(_ is Deferred))
}
/** The set of abstract type members of this type. */
final def abstractTypeMembers(implicit ctx: Context): Seq[SingleDenotation] = track("abstractTypeMembers") {
memberDenots(abstractTypeNameFilter,
(name, buf) => buf += nonPrivateMember(name).asSingleDenotation)
}
/** The set of abstract type members of this type. */
final def nonClassTypeMembers(implicit ctx: Context): Seq[SingleDenotation] = track("nonClassTypeMembers") {
memberDenots(nonClassTypeNameFilter,
(name, buf) => buf += member(name).asSingleDenotation)
}
/** The set of type members of this type */
final def typeMembers(implicit ctx: Context): Seq[SingleDenotation] = track("typeMembers") {
memberDenots(typeNameFilter,
(name, buf) => buf += member(name).asSingleDenotation)
}
/** The set of implicit members of this type */
final def implicitMembers(implicit ctx: Context): List[TermRef] = track("implicitMembers") {
memberDenots(implicitFilter,
(name, buf) => buf ++= member(name).altsWith(_ is Implicit))
.toList.map(d => TermRef.withSig(this, d.symbol.asTerm))
}
/** The set of member classes of this type */
final def memberClasses(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") {
memberDenots(typeNameFilter,
(name, buf) => buf ++= member(name).altsWith(x => x.isClass))
}
final def fields(implicit ctx: Context): Seq[SingleDenotation] = track("fields") {
memberDenots(fieldFilter,
(name, buf) => buf ++= member(name).altsWith(x => !x.is(Method)))
}
/** The set of members of this type having at least one of `requiredFlags` but none of `excludedFlags` set */
final def membersBasedOnFlags(requiredFlags: FlagSet, excludedFlags: FlagSet)(implicit ctx: Context): Seq[SingleDenotation] = track("implicitMembers") {
memberDenots(takeAllFilter,
(name, buf) => buf ++= memberExcluding(name, excludedFlags).altsWith(x => x.is(requiredFlags)))
}
/** The info of `sym`, seen as a member of this type. */
final def memberInfo(sym: Symbol)(implicit ctx: Context): Type =
sym.info.asSeenFrom(this, sym.owner)
/** This type seen as if it were the type of a member of prefix type `pre`
* declared in class `cls`.
*/
final def asSeenFrom(pre: Type, cls: Symbol)(implicit ctx: Context): Type = track("asSeenFrom") {
if (!cls.membersNeedAsSeenFrom(pre)) this
else ctx.asSeenFrom(this, pre, cls)
}
// ----- Subtype-related --------------------------------------------
/** Is this type a subtype of that type? */
final def <:<(that: Type)(implicit ctx: Context): Boolean = track("<:<") {
ctx.typeComparer.topLevelSubType(this, that)
}
/** Is this type a subtype of that type? */
final def frozen_<:<(that: Type)(implicit ctx: Context): Boolean = track("frozen_<:<") {
ctx.typeComparer.isSubTypeWhenFrozen(this, that)
}
/** Is this type the same as that type?
* This is the case iff `this <:< that` and `that <:< this`.
*/
final def =:=(that: Type)(implicit ctx: Context): Boolean = track("=:=") {
ctx.typeComparer.isSameType(this, that)
}
/** Is this type a primitive value type which can be widened to the primitive value type `that`? */
def isValueSubType(that: Type)(implicit ctx: Context) = widen match {
case self: TypeRef if self.symbol.isPrimitiveValueClass =>
that.widenExpr match {
case that: TypeRef if that.symbol.isPrimitiveValueClass =>
defn.isValueSubClass(self.symbol, that.symbol)
case _ =>
false
}
case _ =>
false
}
def relaxed_<:<(that: Type)(implicit ctx: Context) =
(this <:< that) || (this isValueSubType that)
/** Is this type a legal type for a member that overrides another
* member of type `that`? This is the same as `<:<`, except that
* the types `()T`, `=> T` and `T` are seen as overriding
* each other.
*/
final def overrides(that: Type)(implicit ctx: Context) = {
def result(tp: Type): Type = tp match {
case ExprType(_) | MethodType(Nil) => tp.resultType
case _ => tp
}
(this frozen_<:< that) || {
val rthat = result(that)
val rthis = result(this)
(rthat.ne(that) || rthis.ne(this)) && (rthis frozen_<:< rthat)
}
}
/** Is this type close enough to that type so that members
* with the two types would override each other?
* This means:
* - Either both types are polytypes with the same number of
* type parameters and their result types match after renaming
* corresponding type parameters
* - Or both types are method types with =:=-equivalent(*) parameter types
* and matching result types after renaming corresponding parameter types
* if the method types are dependent.
* - Or both types are =:=-equivalent
* - Or phase.erasedTypes is false, and neither type takes
* term or type parameters.
*
* (*) when matching with a Java method, we also regard Any and Object as equivalent
* parameter types.
*/
def matches(that: Type)(implicit ctx: Context): Boolean = track("matches") {
ctx.typeComparer.matchesType(this, that, relaxed = !ctx.phase.erasedTypes)
}
/** This is the same as `matches` except that it also matches => T with T and
* vice versa.
*/
def matchesLoosely(that: Type)(implicit ctx: Context): Boolean =
(this matches that) || {
val thisResult = this.widenExpr
val thatResult = that.widenExpr
(this eq thisResult) != (that eq thatResult) && (thisResult matchesLoosely thatResult)
}
/** The basetype TypeRef of this type with given class symbol,
* but without including any type arguments
*/
final def baseTypeRef(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseTypeRef $base")*/ /*>|>*/ track("baseTypeRef") /*<|<*/ {
base.denot match {
case classd: ClassDenotation => classd.baseTypeRefOf(this)
case _ => NoType
}
}
def & (that: Type)(implicit ctx: Context): Type = track("&") {
ctx.typeComparer.glb(this, that)
}
/** Safer version of `&`.
*
* This version does not simplify the upper bound of the intersection of
* two TypeBounds. The simplification done by `&` requires subtyping checks
* which may end up calling `&` again, in most cases this should be safe
* but because of F-bounded types, this can result in an infinite loop
* (which will be masked unless `-Yno-deep-subtypes` is enabled).
*/
def safe_& (that: Type)(implicit ctx: Context): Type = (this, that) match {
case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => TypeBounds(lo1 | lo2, AndType(hi1, hi2))
case _ => this & that
}
def | (that: Type)(implicit ctx: Context): Type = track("|") {
ctx.typeComparer.lub(this, that)
}
// ----- Unwrapping types -----------------------------------------------
/** Map a TypeVar to either its instance if it is instantiated, or its origin,
* if not, until the result is no longer a TypeVar. Identity on all other types.
*/
def stripTypeVar(implicit ctx: Context): Type = this
/** Remove all AnnotatedTypes wrapping this type.
*/
def stripAnnots(implicit ctx: Context): Type = this
/** Strip PolyType prefix */
def stripPoly(implicit ctx: Context): Type = this match {
case tp: PolyType => tp.resType.stripPoly
case _ => this
}
/** Widen from singleton type to its underlying non-singleton
* base type by applying one or more `underlying` dereferences,
* Also go from => T to T.
* Identity for all other types. Example:
*
* class Outer { class C ; val x: C }
* def o: Outer
* <o.x.type>.widen = o.C
*/
@tailrec final def widen(implicit ctx: Context): Type = widenSingleton match {
case tp: ExprType => tp.resultType.widen
case tp => tp
}
/** Widen from singleton type to its underlying non-singleton
* base type by applying one or more `underlying` dereferences.
*/
@tailrec final def widenSingleton(implicit ctx: Context): Type = stripTypeVar match {
case tp: SingletonType if !tp.isOverloaded => tp.underlying.widenSingleton
case _ => this
}
/** Widen from TermRef to its underlying non-termref
* base type, while also skipping Expr types.
*/
@tailrec final def widenTermRefExpr(implicit ctx: Context): Type = stripTypeVar match {
case tp: TermRef if !tp.isOverloaded => tp.underlying.widenExpr.widenTermRefExpr
case _ => this
}
/** Widen from ExprType type to its result type.
* (Note: no stripTypeVar needed because TypeVar's can't refer to ExprTypes.)
*/
final def widenExpr: Type = this match {
case tp: ExprType => tp.resType
case _ => this
}
/** Widen type if it is unstable (i.e. an ExprType, or TermRef to unstable symbol */
@tailrec final def widenIfUnstable(implicit ctx: Context): Type = stripTypeVar match {
case tp: ExprType => tp.resultType.widenIfUnstable
case tp: TermRef if !tp.symbol.isStable => tp.underlying.widenIfUnstable
case _ => this
}
/** If this is a skolem, its underlying type, otherwise the type itself */
final def widenSkolem(implicit ctx: Context): Type = this match {
case tp: SkolemType => tp.underlying
case _ => this
}
/** Eliminate anonymous classes */
final def deAnonymize(implicit ctx: Context): Type = this match {
case tp:TypeRef if tp.symbol.isAnonymousClass =>
tp.symbol.asClass.typeRef.asSeenFrom(tp.prefix, tp.symbol.owner)
case tp => tp
}
private def dealias(keepAnnots: Boolean)(implicit ctx: Context): Type = this match {
case tp: TypeRef =>
if (tp.symbol.isClass) tp
else tp.info match {
case TypeAlias(tp) => tp.dealias(keepAnnots): @tailrec
case _ => tp
}
case tp: TypeVar =>
val tp1 = tp.instanceOpt
if (tp1.exists) tp1.dealias(keepAnnots): @tailrec else tp
case tp: AnnotatedType =>
val tp1 = tp.tpe.dealias(keepAnnots)
if (keepAnnots) tp.derivedAnnotatedType(tp1, tp.annot) else tp1
case tp: LazyRef =>
tp.ref.dealias(keepAnnots): @tailrec
case app @ HKApply(tycon, args) =>
val tycon1 = tycon.dealias(keepAnnots)
if (tycon1 ne tycon) app.superType.dealias(keepAnnots): @tailrec
else this
case _ => this
}
/** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type
* is no longer alias type, LazyRef, or instantiated type variable.
* Goes through annotated types and rewraps annotations on the result.
*/
final def dealiasKeepAnnots(implicit ctx: Context): Type =
dealias(keepAnnots = true)
/** Follow aliases and dereferences LazyRefs, annotated types and instantiated
* TypeVars until type is no longer alias type, annotated type, LazyRef,
* or instantiated type variable.
*/
final def dealias(implicit ctx: Context): Type =
dealias(keepAnnots = false)
/** Perform successive widenings and dealiasings until none can be applied anymore */
@tailrec final def widenDealias(implicit ctx: Context): Type = {
val res = this.widen.dealias
if (res eq this) res else res.widenDealias
}
/** Widen from constant type to its underlying non-constant
* base type.
*/
final def deconst(implicit ctx: Context): Type = stripTypeVar match {
case tp: ConstantType => tp.value.tpe
case _ => this
}
/** If this is a (possibly aliased, annotated, and/or parameterized) reference to
* a class, the class type ref, otherwise NoType.
* @param refinementOK If `true` we also skip non-parameter refinements.
*/
def underlyingClassRef(refinementOK: Boolean)(implicit ctx: Context): Type = dealias match {
case tp: TypeRef =>
if (tp.symbol.isClass) tp
else if (tp.symbol.isAliasType) tp.underlying.underlyingClassRef(refinementOK)
else NoType
case tp: AnnotatedType =>
tp.underlying.underlyingClassRef(refinementOK)
case tp: RefinedType =>
def isParamName = tp.classSymbol.typeParams.exists(_.name == tp.refinedName)
if (refinementOK || isParamName) tp.underlying.underlyingClassRef(refinementOK)
else NoType
case tp: RecType =>
tp.underlying.underlyingClassRef(refinementOK)
case _ =>
NoType
}
/** The iterator of underlying types as long as type is a TypeProxy.
* Useful for diagnostics
*/
def underlyingIterator(implicit ctx: Context): Iterator[Type] = new Iterator[Type] {
var current = Type.this
var hasNext = true
def next = {
val res = current
hasNext = current.isInstanceOf[TypeProxy]
if (hasNext) current = current.asInstanceOf[TypeProxy].underlying
res
}
}
/** A prefix-less refined this or a termRef to a new skolem symbol
* that has the given type as info.
*/
def narrow(implicit ctx: Context): TermRef =
TermRef(NoPrefix, ctx.newSkolem(this))
/** Useful for diagnostics: The underlying type if this type is a type proxy,
* otherwise NoType
*/
def underlyingIfProxy(implicit ctx: Context) = this match {
case this1: TypeProxy => this1.underlying
case _ => NoType
}
/** If this is a FunProto or PolyProto, WildcardType, otherwise this. */
def notApplied: Type = this
// ----- Normalizing typerefs over refined types ----------------------------
/** If this normalizes* to a refinement type that has a refinement for `name` (which might be followed
* by other refinements), and the refined info is a type alias, return the alias,
* otherwise return NoType. Used to reduce types of the form
*
* P { ... type T = / += / -= U ... } # T
*
* to just U. Does not perform the reduction if the resulting type would contain
* a reference to the "this" of the current refined type, except in the following situation
*
* (1) The "this" reference can be avoided by following an alias. Example:
*
* P { type T = String, type R = P{...}.T } # R --> String
*
* (*) normalizes means: follow instantiated typevars and aliases.
*/
def lookupRefined(name: Name)(implicit ctx: Context): Type = {
@tailrec def loop(pre: Type): Type = pre.stripTypeVar match {