src/rules/suspicious/rewalk.bend checks
raw source on the hub · import 0x013e0f9a479bbebad5ed196725eede95/src/rules/suspicious/rewalk.bend as Rewalk
rule rewalk: one straight piece of a def calls the same walk twice on the
same argument, and one result is used only for a single value (a get of one
index, one field, or a let whose name is only read that way) while the other
result is kept whole. Take the value from that other result. The same
argument is the same text with no let of any name it uses (= or <-,
taking effect at the end of the let) between the two calls. A different
case arm is a different path, and two narrow reads are left alone. A walk is
a def of this file that loops, or a Base walk (List.map and the like).
Laws and proofs do not run (a def with no type at all fills a law: it is a
proof). This is not twice, which is duplicate literals in a list pattern.
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 ../calls.bend as Calls import ../../lazy/lazy.bend as Lazy
Types
type How source · line 20 · raw
Data
how the result of a call is used
HWideHow
HSlotHow
HLet@binder:String -> How
HFieldHow
type Site source · line 27 · raw
Data
one expensive call
Site@name:String -> @args:String -> @line:U32 -> @col:U32 -> @len:U32 -> @how:How -> Site
type Hit source · line 31 · raw
Data
a narrow read and a wide read of one name
Hit@wide:Bool -> @slot:Bool -> Hit
type Slot source · line 35 · raw
Data
where an accessor reads its collection
Slot@on:Bool -> @at:Nat -> Slot
type Pos source · line 39 · raw
Data
a position a mark pass recorded
Pos@line:U32 -> @col:U32 -> Pos
type Lhs source · line 43 · raw
Data
the left of = : one name, and whether a group makes it a field
Lhs@seen:Bool -> @extra:Bool -> @field:Bool -> @nm:String -> Lhs
type Bind source · line 47 · raw
Data
a let of one name, and where it takes effect
Bind@nm:String -> @line:U32 -> @col:U32 -> Bind
type Note source · line 51 · raw
Data
a let whose right-hand side is one call
Note@line:U32 -> @col:U32 -> @how:How -> Note
Definitions
def none_hit source · line 55 · raw
Hit
neither read
def either source · line 59 · raw
@aa:Hit -> @+bb:Hit -> Hit
either read from two results
def name_slot source · line 65 · raw
@+slot:Bool -> Hit
a mention of the name: wide, unless this position is a narrow slot
def name_hit source · line 73 · raw
@+same:Bool -> @+slot:Bool -> Hit
a mention of the name, or nothing when it is a different name
def slot_pick source · line 81 · raw
@+list:Bool -> @+str:Bool -> @+arr:Bool -> Slot
which argument a narrow accessor reads
def slot_of source · line 93 · raw
@+tt:String -> Slot
List.get / head / last / length, String.get / length, Array.get; not List.set
def step_is_zero source · line 100 · raw
@pp:Nat -> Bool
after a comma, still inside the slot argument?
def step_hot_live source · line 108 · raw
@left:Nat -> Bool
after a comma, is the next argument the slot?
def step_hot source · line 116 · raw
@+hot:Bool -> @+left:Nat -> @+live:Bool -> Bool
the slot flag after a comma
def step_left_live source · line 124 · raw
@left:Nat -> Nat
the arguments still to skip after a comma
def step_left source · line 132 · raw
@+left:Nat -> @+live:Bool -> Nat
the arguments still to skip after a comma
def as_open source · line 140 · raw
@+open:Bool -> @tok:0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok -> Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok>
the chain is exactly one call
def as_inside source · line 148 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok>
the inside of one pair of parentheses, when it is exactly a call
def as_wrapped source · line 156 · raw
@+paren:Bool -> @kids:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok>
a parenthesized call, or nothing
def as_call source · line 164 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok>
the chain is exactly one call, or one pair of parentheses around one: its callee
def pos_of source · line 174 · raw
@mm:Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok> -> List<&2, Pos>
the callee, when this argument is exactly a call
def mark_slot source · line 182 · raw
@ss:Slot -> @+as:List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node> -> List<&2, Pos>
the collection argument's call, when this is a narrow accessor
def mark source · line 191 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> List<&2, Pos>
calls that sit in a narrow accessor's collection argument
def here_call source · line 208 · raw
@+call:Bool -> @+tt:String -> @+name:String -> @+hot:Bool -> Hit
the name before a group is a narrow read, a callee, or an ordinary mention
def here_hit source · line 216 · raw
@+brack:Bool -> @+call:Bool -> @+tt:String -> @+name:String -> @+hot:Bool -> Hit
the name before a group is a narrow read, a callee, or an ordinary mention
def inner_hot_call source · line 224 · raw
@+call:Bool -> @+hot:Bool -> Bool
a bracket's inside is cold; a call's arguments start before the slot
def inner_hot source · line 232 · raw
@+brack:Bool -> @+call:Bool -> @+hot:Bool -> Bool
a bracket's inside is cold; a call's arguments start before the slot
def slot_at source · line 240 · raw
@ss:Slot -> Nat
the argument index a slot reads
def inner_left_call source · line 245 · raw
@+call:Bool -> @+tt:String -> Nat
the slot index of a call; a bracket has none
def inner_left source · line 253 · raw
@+brack:Bool -> @+call:Bool -> @+tt:String -> Nat
the slot index of a call; a bracket has none
def slot_on source · line 261 · raw
@ss:Slot -> Bool
whether an accessor has a collection argument
def inner_live_call source · line 266 · raw
@+call:Bool -> @+tt:String -> Bool
only a call's arguments count commas as separators
def inner_live source · line 274 · raw
@+brack:Bool -> @+call:Bool -> @+tt:String -> Bool
only a call's arguments count commas as separators
def has_eq source · line 282 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
does the chain bind?
def hit_keep source · line 292 · raw
@skip:Bool -> @hh:Hit -> Hit
a read counts only once the left of = is over
def pick_hot source · line 300 · raw
@+skip:Bool -> @+brack:Bool -> @+call:Bool -> @+hot:Bool -> Bool
inside a call, unless this chain is still the left of a let
def pick_left source · line 308 · raw
@+skip:Bool -> @+brack:Bool -> @+call:Bool -> @+tt:String -> Nat
inside a call, unless this chain is still the left of a let
def pick_live source · line 316 · raw
@+skip:Bool -> @+brack:Bool -> @+call:Bool -> @+tt:String -> Bool
inside a call, unless this chain is still the left of a let
def hits source · line 325 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+name:String -> @+hot:Bool -> @+left:Nat -> @+live:Bool -> @+skip:Bool -> Hit
reads of the name. hot: this chain is a collection argument. live/left: commas
count toward that argument. skip: ignore names until = (the left of a let)
def narrow_let source · line 357 · raw
@hh:Hit -> Bool
a let of one name is narrow when that name is only read narrowly
def narrow source · line 362 · raw
@hh:How -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
a slot or a field is narrow; a wide use is not; a let depends on the name's reads
def called source · line 374 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> List<&2, String>
every name a node calls
def any_of source · line 389 · raw
@cs:List<&2, String> -> @+set:List<&2, String> -> Bool
does the list hold a name the set has?
def loops.go source · line 396 · raw
@ds:List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/rules/calls.Def> -> @+acc:List<&2, String> -> List<&2, String>
def loops source · line 406 · raw
@ds:List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/rules/calls.Def> -> List<&2, String>
defs of this file that loop
def heavy source · line 410 · raw
@+tt:String -> Bool
Base walks a rewalk cares about
def expensive source · line 417 · raw
@+tt:String -> @+self:String -> @+lp:List<&2, String> -> Bool
a loop of this file, or a Base walk, and not this def itself
def indexed source · line 421 · raw
@rest:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
the rest of the chain indexes the call
def how_of source · line 429 · raw
@+nar:Bool -> How
a slot when the call is indexed, otherwise wide, when the call is expensive
def site_how source · line 437 · raw
@+mine:Bool -> @+nar:Bool -> Maybe<&2, How>
a slot when the call is indexed, otherwise wide, when the call is expensive
def site_list source · line 445 · raw
@mm:Maybe<&2, How> -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> List<&2, Site>
the call as a site, when it is one
def open_site source · line 453 · raw
@+open:Bool -> @+indexed:Bool -> @+tt:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> @+self:String -> @+lp:List<&2, String> -> List<&2, Site>
one site when this application is an expensive call
def names source · line 471 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+acc:List<&2, String> -> List<&2, String>
every name under the node
def lhs_names source · line 485 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+acc:List<&2, String> -> List<&2, String>
the names a let binds: every name left of its = or <-
def last_pos source · line 501 · raw
@ts:List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok> -> Pos
where a let's names take effect: its last token, after the right-hand side
def bind_all source · line 509 · raw
@ns:List<&2, String> -> @+line:U32 -> @+col:U32 -> @+acc:List<&2, Bind> -> List<&2, Bind>
one binding per name, at the let's end
def bind_at source · line 517 · raw
@ns:List<&2, String> -> @pp:Pos -> @+acc:List<&2, Bind> -> List<&2, Bind>
one binding per name, at this position
def binds source · line 522 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+acc:List<&2, Bind> -> List<&2, Bind>
the lets of one straight piece; a case arm is not part of it
def before source · line 537 · raw
@+l1:U32 -> @+c1:U32 -> @+l2:U32 -> @+c2:U32 -> Bool
(l1, c1) comes before (l2, c2)
def count source · line 541 · raw
@bs:List<&2, Bind> -> @+name:String -> @+line:U32 -> @+col:U32 -> U32
how many lets of this name take effect before this position
def stamp source · line 551 · raw
@ns:List<&2, String> -> @+bs:List<&2, Bind> -> @+line:U32 -> @+col:U32 -> String
which binding of each name an argument reads: two calls with the same text read the same values only when no let of those names sits between them
def gather source · line 560 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+self:String -> @+lp:List<&2, String> -> @+bs:List<&2, Bind> -> List<&2, Site>
every expensive call, wide unless the call is indexed on the spot; its arguments are their text and which let of each name they read
def add_seen source · line 579 · raw
@+seen:Bool -> @+extra:Bool -> @+field:Bool -> @+nm:String -> @+tt:String -> Lhs
a second name on the left
def fold_names source · line 587 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @st:Lhs -> Lhs
names inside a field group, which makes the let a field read
def eat source · line 600 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @st:Lhs -> Lhs
the left of =
def note_how source · line 615 · raw
@+field:Bool -> @+nm:String -> How
a field when the left has a group, otherwise a let of that name
def note_none source · line 623 · raw
@mm:Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok> -> Maybe<&2, Note>
nothing, and the maybe is consumed
def note_some source · line 629 · raw
@+field:Bool -> @+nm:String -> @mm:Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok> -> Maybe<&2, Note>
the note when the right-hand side is a call
def note_rhs source · line 637 · raw
@+one:Bool -> @+field:Bool -> @+nm:String -> @mm:Maybe<&2, 0x013e0f9a479bbebad5ed196725eede95/src/syntax/lex.Tok> -> Maybe<&2, Note>
the note for a call, when the left is exactly one name
def rhs_of source · line 645 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> 0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node
the tokens after =
def note_from source · line 655 · raw
@st:Lhs -> @+rhs:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Maybe<&2, Note>
a let or a field binding of exactly one call
def note_st source · line 660 · raw
@+kids:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Maybe<&2, Note>
a let or a field binding of exactly one call
def retag_one source · line 664 · raw
@+hit:Bool -> @how:How -> @+note:How -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> Site
one site, retagged when it is the let's call
def note_line source · line 672 · raw
@nn:Note -> U32
a note's line
def note_col source · line 677 · raw
@nn:Note -> U32
a note's column
def note_how_of source · line 682 · raw
@nn:Note -> How
a note's how
def retag source · line 687 · raw
@sites:List<&2, Site> -> @+note:Note -> List<&2, Site>
sites whose callee is this let's call take its how
def retag_may source · line 699 · raw
@mm:Maybe<&2, Note> -> @sites:List<&2, Site> -> List<&2, Site>
retag when the statement is a let of a call
def apply source · line 707 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @sites:List<&2, Site> -> List<&2, Site>
lets of a call retag that call
def pinned source · line 721 · raw
@+line:U32 -> @+col:U32 -> @ps:List<&2, Pos> -> Bool
this position was marked a collection argument
def pin_wide source · line 731 · raw
@how:How -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> Site
a wide call at a marked position becomes a slot; a let or a field stays
def pin_how source · line 739 · raw
@+hit:Bool -> @how:How -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> Site
a wide call at a marked position becomes a slot
def pin_one source · line 747 · raw
@ps:List<&2, Pos> -> @ss:Site -> Site
one site
def pin source · line 752 · raw
@+ps:List<&2, Pos> -> @sites:List<&2, Site> -> List<&2, Site>
marked collection arguments become slots
def other_full source · line 760 · raw
@+yes:Bool -> @how:How -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
the other site keeps the whole result
def other_go source · line 768 · raw
@sites:List<&2, Site> -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
another site has the same callee and the same arguments, and keeps the whole result
def earlier_nar source · line 780 · raw
@+yes:Bool -> @how:How -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
this earlier site is a narrow read of the same call
def earlier_one source · line 788 · raw
@ss:Site -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
this earlier site is a narrow read of the same call
def earlier source · line 795 · raw
@seen:List<&2, Site> -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> Bool
a narrow site of this call already reported
def report_fresh source · line 805 · raw
@+prior:Bool -> @+name:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> @+path:String -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
the finding when no earlier narrow site took this call
def report_nar source · line 821 · raw
@+nar:Bool -> @+prior:Bool -> @+name:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> @+path:String -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
the finding, when this is the first narrow site of a duplicated call
def report_dup source · line 837 · raw
@+dup:Bool -> @how:How -> @+name:String -> @+args:String -> @+line:U32 -> @+col:U32 -> @+len:U32 -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+path:String -> @+seen:List<&2, Site> -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
the finding when a duplicate exists and this site is the first narrow one
def report_one source · line 857 · raw
@ss:Site -> @+all:List<&2, Site> -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+path:String -> @+seen:List<&2, Site> -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
one site
def report source · line 868 · raw
@sites:List<&2, Site> -> @+all:List<&2, Site> -> @+body:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+path:String -> @+seen:List<&2, Site> -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
the first narrow site of each duplicated call
def local source · line 882 · raw
@+nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+self:String -> @+lp:List<&2, String> -> @+path:String -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
findings in one straight region; a case arm is not part of it
def visit source · line 887 · raw
@nn:0x013e0f9a479bbebad5ed196725eede95/src/syntax/tree.Node -> @+self:String -> @+lp:List<&2, String> -> @+path:String -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
each case arm on its own, so two arms are not one path
def check.go source · line 902 · raw
@ds:List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/rules/calls.Def> -> @+lp:List<&2, String> -> @+path:String -> @acc:List<&2, List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>> -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
def check source · line 917 · raw
@ss:0x013e0f9a479bbebad5ed196725eede95/src/src.Src -> List<&2, 0x013e0f9a479bbebad5ed196725eede95/src/finding.Finding>
the rule