Skip to content

Make string literals owned wherever Rust receives a String [patch] - #228

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/154-rust-string-literal-positions
Oct 14, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/154-rust-string-literal-positions

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #154

What was wrong

#120 added String::from("…"), but only for the return-statement and typed-local paths. Every other place an owned String receives a string literal still wrote a bare &str, and rustc rejected it with E0308: mismatched types (expected String, found &str):

pub const DEFAULT: String = "d";
Self { name: "Anon", nickname: "none" }
return Person { name: "x", nickname: "y" };
self.name = "y";
return (if c { "a" } else { "b" });
pub const NAMES: &[String] = &[ "a", "b" ];

Change (all in RustGenerator)

  • Struct literals: each named field is written through WriteValue using the field's declared type. That covers a constructor's initialisers, a field's declared starting value (which the constructor fills in), and a ConstructionExpression naming the struct. The struct is constructedType for Self, or for its own name inside its impl; otherwise it is looked up in the document with the existing DeclaredTypes(GenerationRoot).
  • Assignment to self.<field>: GenerateAssignmentStatement writes the value using the field's declared type. Only plain = changes; String += "lit" already compiles.
  • Conditionals: WriteValue now recurses into both branches of a ConditionalExpression when the target type is an owned String.
  • Consts and statics: SpellStorageType spells a string as &'static str, and an array of them as &[&'static str]. String::from is not a const fn, so a constant can never hold a String built from a literal. The lifetime is written out because elision in associated consts is being phased out.

Output for the issue's repro now:

pub const DEFAULT: &'static str = "d";
Self { name: String::from("Anon"), nickname: String::from("none") }
return Person { name: String::from("x"), nickname: String::from("y") };
self.name = String::from("y");
return (if c { String::from("a") } else { String::from("b") });
pub const NAMES: &[&'static str] = &[ "a", "b" ];

Tests

  • New RustGeneratedSourceCompilesTests.StringLiteralsFillingStringFieldsAndConstants_Compile. It covers the issue's repro plus a struct literal built outside the type's own impl, a field's declared starting value, a module-level const and static, and a string table. It compiles them with rustc --edition 2021.
  • Before the change it failed with 13 E0308 errors. After the change it passes.
  • Full Coder.Test suite: 1265 passed, 0 failed. dotnet format --verify-no-changes on the touched files reports only the CHARSET/IMPORTS findings that main already has.

Known limits

  • A string constant is now &'static str. Code that reads such a constant where a String is expected (for example return Self::DEFAULT; from a function returning String) still needs a conversion. That is the same kind of bug in another position, but it is not one of the five this issue lists.
  • A string constant whose initialiser is a call (not a literal) is also spelled &'static str. No reported case needs anything else, and String::from couldn't appear there anyway.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NW9fJSB9VKsuPv7M2UmznC


Generated by Claude Code

#120 wrote String::from("…") for a literal returned as, or initialising a
local typed as, an owned String, but every other place a String receives
a literal still wrote a bare &str and failed with E0308.

- A struct literal's field, whether built by a constructor's initialisers,
  from a field's declared starting value, or by a construction naming the
  struct, is written for the type the field was declared with. The struct
  is the one whose impl is being written for Self, and is looked up in the
  document otherwise.
- An assignment to a field of self is written for the field's type.
- A conditional answering a String writes each branch as one.
- A const or static declared as a string is a &'static str, and a table
  of them a &[&'static str]: String::from is not a const fn, so no
  constant can hold a String built from a literal.

Fixes #154

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NW9fJSB9VKsuPv7M2UmznC
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 7018370 into main Oct 14, 2026
16 checks passed
@matt-edmondson
matt-edmondson deleted the fix/154-rust-string-literal-positions branch October 14, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants