Attempt u[x_] := x; Trace[x*u[x] /. x -> 2] u[x_] := x; Trace[x*u[x] /. x -> 2] u[x_] := x; Trace[x*u[x] /. x -> 2] first evaluates x and u[x] . In this case, he first tries to evaluate fact[x-1] before replacing x with 2 and falls into the recursion limit.
Attributes[ReplaceAll] shows that it does not have a HoldFirst attribute, so it starts by evaluating its first argument. For example,
ReleaseHold@ReplaceAll [Hold[x*fact[x - 1]], x -> 2]
gives the expected 2 , because it contains the first argument, replaces, and then releases the hold, as you expected.
Another way to do this is
Unprotect[ReplaceAll] SetAttributes[ReplaceAll, HoldFirst] ReplaceAll[x*fact[x - 1], x -> 2]
but do not do it.
Of course, someone will soon give a better explanation.
EDIT: in response to an added question about why
Clear[factif] factif[n_] := If[n < 1, 1, n factif[n - 1]]
does not lead to infinite recursion: it is defined in this way, factif[x] is evaluated as If[x < 1, 1, x factif[x - 1]] , since x<1 cannot be estimated. Thus, it remains in this form after trying to evaluate the first argument of ReplaceAll , then a replacement occurs, etc.