A suggestion which sidesteps most of @nrc’s concerns (except parsing) would be to treat {a: i8, b: u32} as a ‘struct literal’ similar to ‘integer literals’ whose specific type gets resolved by inference. So you’d have
struct Options {
foo: String,
bar: f32 = 2.5, // default args
baz: u32 = 10,
}
fn do_something(options: Options) { /* ... */ }
do_something({foo: "oh no!".to_owned()});
let options = {foo: "hello".to_owned(), baz: 24};
/*...*/
do_something(options); // type of `options` gets resolved to `Options` and
// missing arguments filled in.
Layout, repr etc still get decided on the Options struct, without any additional syntax, but you still gain the ergonomics (in particular around not having to import additional types). @iopq suggested types can be added backwards compatibly (with unspecified layout/repr—similar to tuples) and can serve as the i32 fallback equivalent to a struct literal.