~/bend-docscommunity

src/rules/suspicious/eager.bend checks

raw source on the hub · import 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/rules/suspicious/eager.bend as Eager

rule eager: a branch of a Bool.pick calls a recursive def of the same file. Bool.pick is an ordinary def, so both branch arguments are evaluated before the call: the work in a branch runs whatever the condition says, and the condition never saves it. pick catches the self-call and strict the one under Bool.and/or; a call to a neighbour is the same bug and neither sees it (a game's overlap test moved out of a pick branch took a scene from 31 to 55 fps; one gaps(..) in a branch here ran on every file the linter read, 88 s of a 100 s run). Bind the call above the pick (+x = gaps(..)), or take the branch lazily (Lazy.stop, Lazy.or_else from src/lazy/lazy.bend: the last argument is a Unit -> T thunk, applied only on the branch that needs it). Two things keep it off idiomatic code: only a call to a def of this file counts, and only to one that loops (it calls itself, or reaches something that does), since a Base call and a one-line accessor are everywhere and cost nothing; only the branch arguments count, not the type and the condition, which run whatever is written; and what sits after a => is a lambda's body, which the call does not run. The body ends at the next comma of its group, so an argument after it counts again.

7 imports
import Base
import ../../src.bend as Src
import ../../finding.bend as F
import ../../syntax/lex.bend as Lex
import ../../syntax/tree.bend as Tree
import ../../lazy/lazy.bend as Lazy
import ../calls.bend as Calls

Definitions

def called source · line 27 · raw

@nn:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> List<&2, String>

every name a node calls, f(..), at any depth

def any_of source · line 42 · raw

@cs:List<&2, String> -> @+set:List<&2, String> -> Bool

does the list hold a name the set has?

def loops.go source · line 49 · raw

@ds:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/rules/calls.Def> -> @+acc:List<&2, String> -> List<&2, String>

def loops source · line 61 · raw

@ds:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/rules/calls.Def> -> List<&2, String>

the defs of the file that loop: one that calls itself, or that reaches one that does (a def is defined above its use and there is no mutual recursion, so one pass down the file settles it)

def work.hot source · line 68 · raw

@kk:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.TokKind -> @+hot:Bool -> @+seg:U32 -> @+keep:Bool -> Bool

the hot a leaf leaves behind: a => clears it for the lambda's body; a comma of a pick's own group moves to its next argument, hot from the third on (0 the type, 1 the condition, 2 and 3 the branches), and a comma of any other group returns it to keep; any other leaf leaves it as it was

def work.seg source · line 80 · raw

@kk:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.TokKind -> @+seg:U32 -> U32

the argument a leaf leaves behind: a comma of a pick's own group moves on

def work.name source · line 88 · raw

@kk:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/lex.TokKind -> Bool

can the leaf name a call (it is neither a => nor a comma)?

def work source · line 105 · raw

@nn:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/syntax/tree.Node -> @+ns:List<&2, String> -> @+self:String -> @+path:String -> @+hot:Bool -> @+seg:U32 -> @+keep:Bool -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

the work under a def's body: hot says the node sits in a branch argument of a Bool.pick (so it runs whatever the condition), seg counts the arguments of the pick whose group this chain is (0 the type, 1 the condition, 2 and 3 the branches; 9 for a chain that is not a pick's), and keep is what hot returns to at the next comma of a chain that is not a pick's, so a => clears hot for the lambda's own body and not for the arguments after it. A leaf moves the state by its kind (work.hot, work.seg); a => or a comma before a group names no call, so that group is walked as any other

def check.go source · line 143 · raw

@ds:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/rules/calls.Def> -> @+ns:List<&2, String> -> @+path:String -> @acc:List<&2, List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

def check source · line 158 · raw

@ss:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/src.Src -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>

the rule