RuleDelayed::rhs is not an error message but rather a warning message. This is an important distinction. If you know what you are doing the message can be safely ignored. This is also the case with Pattern::patv.(1)(2)
I would say that your method as written is not safe however for a different reason: it evaluates the Symbols m and n which means your code breaks if these are defined. Please consider this as an alternative:
SetAttributes[replacementRule, HoldAll]
replacementRule[expr_, {var__Symbol}] :=
(Unevaluated[expr] /.
Thread[Thread @ HoldPattern @ {var} -> Thread @ Pattern[{var}, _]]) :> expr
Test:
m := Print["fail!"];
replacementRule[h[m, n], {m, n}]
h[m_, n_] :> h[m, n]
Or instead using Block to guard against evaluation:
ClearAll[replacementRule]
SetAttributes[replacementRule, HoldAll]
replacementRule[expr_, var : {__Symbol}] :=
Block[var,
Unevaluated[expr] /. Thread[var -> (Pattern[#, _] & /@ var)]
] :> expr
Further thoughts
Both examples above manage to avoid RuleDelayed::rhs by not having an explicit var_ in the body of the definition, but that should not be taken to mean that this is actually superior to methods that do trigger the warning.
Here is a third approach that is more similar to your original method:
ClearAll[replacementRule]
Attributes[replacementRule] = {HoldAll};
replacementRule[expr_, {var__Symbol}] :=
(Unevaluated[expr] /. x : HoldPattern[Alternatives[var]] :> x_) :> expr
This is somewhat more streamlined than my first method with repeated use of Thread but it throws a warning message when used:
replacementRule[h[m, n], {m, n}]
RuleDelayed::rhs: Pattern x\$_ appears on the right-hand side of rule x\$:HoldPattern[m|n]:>x\$_. >>
h[m_, n_] :> h[m, n]
(The appearance of x$ comes from the automatic renaming that takes place in nested scoping constructs of which RuleDelayed is one, despite its not being specifically advertised as such. I started an answer which Leonid Shifrin greatly expanded regarding this that you should eventually read.)
It would in my opinion be entirely acceptable to suppress that warning with Quiet:
ClearAll[replacementRule]
Attributes[replacementRule] = {HoldAll};
replacementRule[expr_, {var__Symbol}] :=
Quiet[
Unevaluated[expr] /. x : HoldPattern[Alternatives[var]] :> x_,
RuleDelayed::rhs
] :> expr
In retrospect I think I prefer this to my earlier recommendation.
head[a_] :> head[a_]withhead[a_] :> With[{b = a}, head[b_]]? – kglr Jul 30 '16 at 23:18