First of all, I think you found a mistake here.
Secondly, I think I can offer some insight into why this happens, bearing in mind that my knowledge of mathematics is limited.
Type operator: f [z_]: = 2 z in full form:
SetDelayed[f[Pattern[z, Blank[]]], 2 z]
This sets the value of DownValue [f]:
{HoldPattern[f[z_]] :> 2 z}
Then later, when an expression like f [2] is later evaluated, the following is true:
f[2] /. HoldPattern[f[z_]] :> 2 z
That will be evaluated to 4. Now all this is possible, because pattern matching occurs with the template [z, Blank []] from the first code block. This works even if you firmly set z to a number. In other words.
z = 5; f[z_] := 2*z
Still produces the same down for f:
{HoldPattern[f[z_]] :> 2 z}
This is possible because the template has a HoldFirst attribute.
The HoldFirst attribute is not sufficiently protected if you evaluate it inside a module. Example:
SetAttributes[tmp, HoldFirst]; Module[{expr}, expr = 2 z; tmp[expr] ]
outputs:
tmp[expr$8129]
I suggest, because the HoldFirst attribute does not provide immunity to the rule for rewriting a module variable, that any template in a rule that contains a local variable overwrites template variables. sim-> Symbol [SymbolName [SYM] ~~ "$"]
Module[{expr}, Hold[z_ -> (z; expr)] ] (*Hold[z$_ -> (z$; expr$1391)]*)
z was rewritten on both sides of the rule in a simple alpha transform.
If the rule does not contain a local variable, rewriting is not performed:
Module[{expr}, Hold[z_ -> (z)] ] (*Hold[z_ -> z]*)
Instead of looking to see if the local variable matches the rule variable, the above rule applies.
So the problem is that the local expr is not evaluated before alpha conversion occurs. Or maybe it would be even better to have expr wrapped in the lazily evaluated alpha transform that RuleDelayed would need.
This does not happen in the block, because Block does not overwrite any of the local variables.
Any other ideas? Does anyone see any holes in my logic?