References are the purview of the borrow checker, naturally, but (assuming that you care about memory safety) you might be able to get away with a system that doesn't let you store arbitrary references, but conceivably you could have some kind of simple-ish scope-based analysis that might allow the compiler to transparently elide copies when passing owned values to functions deeper in the call stack. A mechanism to reify the notion of strictly-scoped values in the language (like Python's `with` statement) could probably go quite far here, allowing your compiler to know that a piece of data is anchored to a given scope which strictly outlives some child scopes, allowing a reference to that data to remain valid for those child scopes. You'd still have to have Rust's notion of aliasing XOR mutation, but if references are first-class values this might be tractable, because you get much of this for free from an ownership system (mutable references are owned, immutable references are copyable), although Rust has several other ways that it bends over backwards to make this work nicely (e.g. compiler-inserted reborrowing). If you wanted to avoid this complexity you could start by just sticking to only having immutable references that allow copying the inner data if you want to mutate it.