Best Model for Rust: The Borrow Checker Is Your Evaluator
Models

Best Model for Rust: The Borrow Checker Is Your Evaluator

Rust punishes weak models loudly rather than quietly. Why iterations-to-green is the metric that matters and where models predictably fail.

Rust inverts the usual risk of AI-generated code. In most languages a weak model produces something that runs and is subtly wrong. In Rust a weak model produces something that does not compile, and you find out in seconds.

That is a much better failure mode, and it means the question to ask about a model is not whether it writes correct Rust. It is how many compiler round trips it needs to get there, because that number is what you actually pay in time and tokens.

Less training data, better feedback

Two forces pull in opposite directions. Rust is less represented in training corpora than Python or JavaScript, so raw first-attempt quality is lower across the whole field. But rustc produces the best error messages of any mainstream compiler, frequently naming the exact fix.

The second force is stronger than the first if your loop is set up to use it. A model that fails on the first attempt but reads a borrow-checker error and applies the suggested change will converge. A model that fails and then produces a differently broken version will not.

So the discriminating test is not first-attempt compile rate. It is whether the model makes progress across iterations, which is exactly the property that error recovery patterns describes for agents in general.

Where models predictably fail

Three areas account for most of it, and they are worth recognising because each has a different workaround.

Lifetimes are the first. Models produce code that works for simple ownership and then reach for a lifetime annotation they do not fully understand when a reference outlives its scope. The output often compiles after a struggle but with lifetimes that are more restrictive than necessary, which causes problems at the next call site.

Async is the second, and it is worse. Pinning, futures that are not Send, and holding a lock across an await point are all things models get wrong routinely, and the last one compiles fine and deadlocks under load. That is the rare Rust failure that is silent.

Trait resolution is the third. Complex generic bounds, blanket implementations and the orphan rule produce errors models find hard to reason backwards from. Here the compiler message is long and models sometimes fixate on the wrong part of it.

The clone-and-unwrap escape hatch

When a model cannot satisfy the borrow checker, it does not usually give up. It works around, and the workarounds have a signature.

Excessive clone() is the most common: rather than restructure ownership, the model copies the data. It compiles, it is correct, and it quietly discards the performance characteristics that were the reason to use Rust.

unwrap() is the second. Faced with a Result it does not want to thread through, the model unwraps and moves on, converting a compile-time obligation into a runtime panic.

Reference counting is the third — wrapping everything in shared pointers to make the ownership problem disappear. All three pass review from anyone who is only checking that it builds, which is why "it compiles" is a weak acceptance criterion for generated Rust specifically.

Compile time makes iteration expensive

The compiler loop that makes Rust attractive for AI-generated code also has a cost that the Python and TypeScript equivalents do not. A cold build on a substantial crate is minutes, not seconds.

An agent that iterates ten times on a large project spends most of its wall-clock time waiting. That changes the calculation: a stronger model that gets closer on the first attempt is worth more here than in a language where the verifier is instant.

Mitigate it with cargo check rather than full builds during iteration, which skips code generation and returns type and borrow errors in a fraction of the time. Reserve full builds for when the check passes. This one change often halves the wall-clock cost of a Rust agent loop.

Measure iterations to green

The right benchmark for Rust model selection is one you can run in an afternoon. Take twenty real tasks from your own crate — a new function, a trait implementation, an async handler, a refactor across modules. Run each through the model with a check-and-retry loop capped at five attempts.

Record three numbers: how many reached a clean check, the mean iterations for those that did, and the total tokens spent. That gives you cost per compiling change, which is the number that actually decides.

Then read a sample of the output for clones, unwraps and unnecessary reference counting. A model with a low iteration count and a high clone rate is not the winner it appears to be. Benchmarking on your own work covers building the harness.

Recommendation

Rust is a case where the stronger models earn their price. Kimi K3 and GLM-5.2 are the reasonable defaults, because fewer iterations matter more when each iteration costs a compile, and because lifetime and trait reasoning is precisely the kind of constrained problem where capability shows.

Cheap models are viable for mechanical work — deriving implementations, writing tests against an existing API, mechanical refactors — where the borrow checker is not being stressed. They are a poor choice for async or anything with non-trivial ownership.

Whichever you use, run clippy as well as the compiler. It catches most of the clone-and-unwrap pattern that rustc happily accepts, and a lint gate is cheaper than a review comment. The contrast with generating Go is instructive: Go models compile easily and fail at runtime, Rust models fail loudly and compile correctly, and the tooling you need differs accordingly. When a model does produce something that builds and misbehaves, choosing a model for debugging covers the next step.

Common questions

Does Rust need a stronger model than other languages?

Generally yes, for two reasons. Rust is less represented in training data, and each iteration costs a compile rather than a second of type checking, so getting closer on the first attempt is worth more.

If the generated Rust compiles, is it good?

Not necessarily. Models escape the borrow checker with excessive cloning, unwrap on Results, and reference counting to make ownership problems disappear. All three compile. Run clippy as a gate to catch them.

How do I make a Rust agent loop faster?

Use cargo check rather than full builds during iteration. It skips code generation and returns type and borrow errors in a fraction of the time, and full builds can wait until the check passes.

Similar articles

A/B Testing Two Models Without Fooling Yourself
Models
Models·9 min read

A/B Testing Two Models Without Fooling Yourself

Comparing two models on live traffic sounds simple and usually is not. Sample sizes, paired designs, and the metrics that actually settle the question.

Read
The Artificial Analysis Index Explained: What It Does Measure
Models
Models·9 min read

The Artificial Analysis Index Explained: What It Does Measure

A single number that ranks every model is convenient and easy to misread. What the AA Intelligence Index aggregates, and where it stops being useful.

Read
Best Model for Agentic Workflows: Reliability Compounds
Models
Models·9 min read

Best Model for Agentic Workflows: Reliability Compounds

An agent that is 95 percent reliable per step fails most thirty-step tasks. Why compounding error, not peak capability, decides which model to run in a loop.

Read