v3: fix self-host convergence; cgen: fix ?T == ?T option equality#27640
v3: fix self-host convergence; cgen: fix ?T == ?T option equality#27640medvednikov wants to merge 2 commits into
?T == ?T option equality#27640Conversation
…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).
?T == ?T option equality
There was a problem hiding this comment.
💡 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".
| // 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}' |
There was a problem hiding this comment.
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 👍 / 👎.
Two changes.
1. v3: fix self-host (
vlib/v3/*)Fixes four stacked bugs that broke
v3 -building-v/-selfhost(surfaced byv -gc none -prod -o v3 v3.v && ./v3 -building-v -o v4 v3.v). Each masked the next:cannot redeclare C struct C.termios— two causes:pref.file_has_incompatible_os_suffixwas missing_qnx/_serenity/_plan9/_vinix/_haiku/_termux, sotermios_qnx.c.vleaked into thetermiosmodule on macOS and collided withtermios_darwin.c.v(same module).termandterm.termioseach legitimately mirrorC.termioswith different fields (intvsusize). The redeclaration check is now scoped per module (production V has no cross-module C-struct check at all).convert_t_to_voidptrundeclared — inbuilding_v/selfhostmode 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 samefn_decl_has_unresolved_genericsdetector as the monomorphize path.Array_fixed_int_0undeclared / bogusmemcmp) —gen_fixed_array_infix_eqdetected fixed arrays via a defaultArrayFixed{}sentinel andelem_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) intomemcmp(..., sizeof(Array_fixed_int_0)). Now detects fixed-array operands by the optional's presence, never inspecting a default sentinel.Verification
-building-vchain converges byte-identical: v4 == v5 == v6 (2999488 bytes).-selfhostchain converges: v5.c == v6.c (thetest_all.vshcheck) and v5 == v6.c_struct_redeclaration_test.vpasses (same-module redeclarations still error).builtin/array_testandarrays/arrays_testfail identically on cleanmaster(pre-existing, unrelated).2. cgen: fix
?T == ?Twhen 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: bothnone→ equal; differing none-ness → not equal; otherwise unwrap and compare with the base type's==(resolving the correctbuiltin__/generic/alias method name and honoring pointer-receiver eq).