-
Notifications
You must be signed in to change notification settings - Fork 39
Description
Проблема
В присваивании, блоке или вложенной функции легко забыть записать крышку у переопределяемой переменной. Типичный пример — коммит a21d2d9.
В лучшем случае потеря крышки приведёт к снижению быстродействия (т.к. переменная сначала копируется, а потом сравнивается на равенство), в худшем — внесётся ошибка (т.к. значение переменной может быть иным).
Решение
Ну, очевидно нужно отлавливать такие случаи и выдавать на них предупреждение. Причём указывать можно непосредственно на переменную — переменные в дереве у Checker.ref’а имеют координаты.
Засада
Засада в том, что повторная переменная может быть намеренной частью алгоритма. Например:
refal-5-lambda/src/compiler/OptTree.ref
Lines 51 to 68 in 1058511
| DoOptTree { | |
| 0 t.OptDrive s.OptSpec s.OptAutoMarkup e.AST = 0 e.AST; | |
| s.Cycles t.OptDrive s.OptSpec s.OptAutoMarkup e.AST | |
| = <Log-AST ('Pass ' <Symb s.Cycles> ' (before Auto markup)') e.AST> : e.AST^ | |
| = e.AST : e.OriginAST | |
| = <OptTree-AutoMarkup s.OptAutoMarkup e.AST> : e.AST^ | |
| = <Dec s.Cycles> : s.Cycles^ | |
| = <DriveSpecLoop s.Cycles t.OptDrive s.OptSpec e.AST> : s.Cycles^ e.AST^ | |
| = e.AST | |
| : { | |
| e.OriginAST = s.Cycles e.OriginAST; | |
| e.AST^ = <DoOptTree s.Cycles t.OptDrive s.OptSpec s.OptAutoMarkup e.AST>; | |
| } | |
| } |
refal-5-lambda/src/compiler/OptTree.ref
Lines 82 to 94 in 1058511
| DoDriveSpecLoop { | |
| 0 t.OptDrive s.OptSpec e.AST = 0 e.AST; | |
| s.Cycles t.OptDrive s.OptSpec e.AST | |
| = e.AST : e.OriginAST | |
| = <DriveLoop s.Cycles t.OptDrive e.AST> : s.Cycles^ e.AST^ | |
| = <SpecPass s.Cycles s.OptSpec e.AST> : s.Cycles^ e.AST^ | |
| = e.AST | |
| : { | |
| e.OriginAST = s.Cycles e.OriginAST; | |
| e.AST^ = <DoDriveSpecLoop s.Cycles t.OptDrive s.OptSpec e.AST>; | |
| } | |
| } |
refal-5-lambda/src/compiler/OptTree.ref
Lines 105 to 119 in 1058511
| DoDriveLoop { | |
| 0 t.OptDrive e.AST = 0 e.AST; | |
| s.Cycles t.OptDrive e.AST | |
| = <Log-AST ('Pass ' <Symb s.Cycles> ' (before Drive)') e.AST> : e.AST^ | |
| = e.AST : e.OriginAST | |
| = <ExpandClosures e.AST> : e.AST^ | |
| = <OptTree-Drive t.OptDrive e.AST> : e.AST^ | |
| = <Dec s.Cycles> : s.Cycles^ | |
| = e.AST | |
| : { | |
| e.OriginAST = s.Cycles e.OriginAST; | |
| e.AST^ = <DoDriveLoop s.Cycles t.OptDrive e.AST>; | |
| }; | |
| } |
Все три примера проверяют, что дерево осталось неизменным с предыдущей итерации. Поэтому просто выдавать предупреждения на повторные переменные в образцах блоков и вложенных функций нельзя — будет много ложноположительных срабатываний.
Повторная переменная может быть ключом при ассоциативном поиске (по открытой переменной), а значит, тоже является частью алгоритма.
Наиболее консервативной (но и наиболее слабой) эвристикой можно рассматривать повторные переменные в присваиваниях с жёсткими образцами. Но этого мало. Нужны более тонкие эвристики для блоков и вложенных функций.