In the Rust grammar, let occurs in condition sub-expressions within if and while expressions, as well as in one of the four alternative productions for statements.
In my experience, relatively few = assignment statements are instances of delayed initialization of immutable variables. If that’s also the case for the OP, they could handle those cases by annotating only those assignment statements:
let foo;
\*!mut*\ foo = bar;
All other assignment statements [added: without a let prefix] in the program would be presumed to be assignments or reassignments to mut variables.
For the record, here are the current instances of the “mut” keyword in the productions of the draft grammar for Rust that is being developed by the grammar-wg. (In the following, … means that the production contains other alternatives that are not shown.)
Expr = attrs:OuterAttr* kind:ExprKind;
ExprKind = …
| Borrow:{ "&" mutable:"mut"? expr:Expr }
Item = attrs:OuterAttr* vis:Vis? kind:ItemKind;
ItemKind = …
| Static:{ "static" mutable:"mut"? name:IDENT ":" ty:Type "=" value:Expr ";" }
ForeignItem = attrs:OuterAttr* vis:Vis? kind:ForeignItemKind;
ForeignItemKind = …
| Static:{ "static" mutable:"mut"? name:IDENT ":" ty:Type ";" }
FnArg = …
| SelfValue:{ mutable:"mut"? "self" }
| SelfRef:{ "&" lt:LIFETIME? mutable:"mut"? "self" }
Pat = …
| Ref:{ "&" mutable:"mut"? pat:Pat }
Binding = boxed:"box"? reference:"ref"? mutable:"mut"? name:IDENT;
Type = …
| RawPtr:{ "*" { "const" | mutable:"mut" } pointee:Type }
| Ref:{ "&" lt:LIFETIME? mutable:"mut"? pointee:Type }