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+ 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