1
+ package dotty .tools .dotc
2
+ package transform
3
+
4
+ import core .*
5
+ import MegaPhase .MiniPhase
6
+ import Contexts .* , Types .* , Symbols .* , SymDenotations .* , Flags .*
7
+ import ast .*
8
+ import Trees .*
9
+ import Decorators .*
10
+
11
+ import annotation .threadUnsafe
12
+
13
+ object CheckLoopingImplicits :
14
+ val name : String = " checkLoopingImplicits"
15
+
16
+ /** Checks that implicit defs do not call themselves in an infinite loop */
17
+ class CheckLoopingImplicits extends MiniPhase :
18
+ thisPhase =>
19
+ import tpd ._
20
+
21
+ override def phaseName : String = CheckLoopingImplicits .name
22
+
23
+ override def transformDefDef (mdef : DefDef )(using Context ): DefDef =
24
+ val sym = mdef.symbol
25
+
26
+ def checkNotSelfRef (t : RefTree ) =
27
+ if t.symbol eq sym then
28
+ report.warning(
29
+ em """ Infinite loop in function body
30
+ | ${mdef.rhs}""" ,
31
+ mdef.rhs.srcPos
32
+ )
33
+
34
+ def checkNotLooping (t : Tree ): Unit = t match
35
+ case t : Ident =>
36
+ checkNotSelfRef(t)
37
+ case t @ Select (qual, _) =>
38
+ checkNotSelfRef(t)
39
+ checkNotLooping(qual)
40
+ case Apply (fn, args) =>
41
+ checkNotLooping(fn)
42
+ fn.tpe.widen match
43
+ case mt : MethodType =>
44
+ args.lazyZip(mt.paramInfos).foreach { (arg, pinfo) =>
45
+ if ! pinfo.isInstanceOf [ExprType ] then checkNotLooping(arg)
46
+ }
47
+ case _ =>
48
+ case TypeApply (fn, _) =>
49
+ checkNotLooping(fn)
50
+ case Block (stats, expr) =>
51
+ stats.foreach(checkNotLooping)
52
+ checkNotLooping(expr)
53
+ case Typed (expr, _) =>
54
+ checkNotLooping(expr)
55
+ case Assign (lhs, rhs) =>
56
+ checkNotLooping(lhs)
57
+ checkNotLooping(rhs)
58
+ case If (cond, _, _) =>
59
+ checkNotLooping(cond)
60
+ case Match (selector, _) =>
61
+ checkNotLooping(selector)
62
+ case Labeled (_, expr) =>
63
+ checkNotLooping(expr)
64
+ case Return (expr, _) =>
65
+ checkNotLooping(expr)
66
+ case WhileDo (cond, _) =>
67
+ checkNotLooping(cond)
68
+ case Try (block, _, finalizer) =>
69
+ checkNotLooping(block)
70
+ checkNotLooping(finalizer)
71
+ case SeqLiteral (elems, _) =>
72
+ elems.foreach(checkNotLooping)
73
+ case t : ValDef =>
74
+ if ! t.symbol.is(Lazy ) then checkNotLooping(t.rhs)
75
+ case _ =>
76
+
77
+ if sym.isOneOf(GivenOrImplicit ) then
78
+ checkNotLooping(mdef.rhs)
79
+ mdef
80
+ end transformDefDef
81
+ end CheckLoopingImplicits
0 commit comments