Skip to content

v3: fix self-host convergence; cgen: fix ?T == ?T option equality#27640

Open
medvednikov wants to merge 2 commits into
masterfrom
v3-fix-selfhost-convergence
Open

v3: fix self-host convergence; cgen: fix ?T == ?T option equality#27640
medvednikov wants to merge 2 commits into
masterfrom
v3-fix-selfhost-convergence

Conversation

@medvednikov

@medvednikov medvednikov commented Jul 3, 2026

Copy link
Copy Markdown
Member

Two changes.

1. v3: fix self-host (vlib/v3/*)

Fixes four stacked bugs that broke v3 -building-v / -selfhost (surfaced by v -gc none -prod -o v3 v3.v && ./v3 -building-v -o v4 v3.v). Each masked the next:

  1. cannot redeclare C struct C.termios — two causes:
    • pref.file_has_incompatible_os_suffix was missing _qnx/_serenity/_plan9/_vinix/_haiku/_termux, so termios_qnx.c.v leaked into the termios module on macOS and collided with termios_darwin.c.v (same module).
    • term and term.termios each legitimately mirror C.termios with different fields (int vs usize). The redeclaration check is now scoped per module (production V has no cross-module C-struct check at all).
  2. convert_t_to_voidptr undeclared — in building_v/selfhost mode generic templates are erased, but the erasure collector used a weak literal-'generic'-substring scan that missed methods whose only generic param comes from the receiver struct (fn (t ThreadLocalStorage[T]) set(value T)). The helper got erased but its caller didn't. Now uses the same fn_decl_has_unresolved_generics detector as the monomorphize path.
  3. Self-host convergence (Array_fixed_int_0 undeclared / bogus memcmp)gen_fixed_array_infix_eq detected fixed arrays via a default ArrayFixed{} sentinel and elem_type !is types.Void. The zero value of that sum-type field is not reliable across bootstrap generations, so a later generation miscompiled every scalar != 0 (e.g. @[flag] enum .has()(a.flags & 32) != 0) into memcmp(..., sizeof(Array_fixed_int_0)). Now detects fixed-array operands by the optional's presence, never inspecting a default sentinel.

Verification

  • -building-v chain converges byte-identical: v4 == v5 == v6 (2999488 bytes).
  • -selfhost chain converges: v5.c == v6.c (the test_all.vsh check) and v5 == v6.
  • c_struct_redeclaration_test.v passes (same-module redeclarations still error).
  • No new regressions: builtin/array_test and arrays/arrays_test fail identically on clean master (pre-existing, unrelated).

2. cgen: fix ?T == ?T when base type has a defined == (vlib/v/gen/c/infix.v)

Comparing two options whose base type has a defined equality (e.g. ?string, or a struct/alias with an operator overload) derived the eq function name from the option-wrapped type, producing an undefined _option_T__eq. Now handled option-awarely: both none → equal; differing none-ness → not equal; otherwise unwrap and compare with the base type's == (resolving the correct builtin__/generic/alias method name and honoring pointer-receiver eq).

…eq convergence)

Fixes four stacked bugs that broke `v3 -building-v`/`-selfhost`, each masking the next:

- pref: add missing OS suffixes (_qnx/_serenity/_plan9/_vinix/_haiku/_termux) to
  file_has_incompatible_os_suffix, so termios_qnx.c.v no longer leaks into the
  `termios` module on non-QNX targets and collides with the darwin variant.
- checker: scope the C-struct redeclaration check per module. A C struct name maps
  to one external C type, but different modules may each mirror it with their own
  field view (e.g. C.termios in both `term` and `term.termios`). Only same-module
  redeclarations are a real conflict.
- transform: erase_generic_templates now uses the same fn_decl_has_unresolved_generics
  detector as the monomorphize path, so methods whose only generic param comes from
  the receiver struct (e.g. `fn (t ThreadLocalStorage[T]) set(value T)`) are erased in
  building_v mode instead of emitting a raw `_T_` body calling erased helpers.
- cgen: gen_fixed_array_infix_eq detects fixed-array operands by the optional's
  presence instead of inspecting a default-constructed ArrayFixed{} sentinel. The zero
  value of the elem_type sum-type field is not reliably Void across bootstrap
  generations, which made a later generation miscompile scalar `!= 0` (e.g. @[flag]
  enum `.has()`) into a bogus memcmp against Array_fixed_int_0.

Both self-host chains now converge byte-identically: -building-v (v4==v5==v6) and
-selfhost (v5.c==v6.c, the test_all.vsh check).
@medvednikov medvednikov changed the title v3: fix self-host (C.termios redeclare, generic erasure, fixed-array eq convergence) v3: fix self-host convergence; cgen: fix ?T == ?T option equality Jul 3, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a9f51c26dd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v3/types/checker.v
// their own field view (e.g. `C.termios` in both `term` and
// `term.termios`). Only redeclarations within the same module are
// a genuine conflict.
key := '${tc.cur_module}|${qname}'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Don’t scope C redeclarations without scoped fields

When two imported modules declare different field views of the same C.Foo, this lets both declarations pass, but the rest of TypeChecker.collect() still stores fields globally under only tc.structs[qname], so the later module’s fields are used for selectors/codegen in both modules. In that scenario a valid use of the first module’s view can be rejected or mis-typed depending on collection order; either the C struct field tables need the same module scoping or the duplicate check should still protect cases with conflicting field views.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant