Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5de95fd
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
7176fa1
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
62597c2
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
8fe6349
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
448b5a6
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
f06aa0c
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
bc94456
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
4a7fcea
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
70f43a7
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 14, 2026
73d6049
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 15, 2026
b9f64f6
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 15, 2026
b0e8536
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 15, 2026
be629aa
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 15, 2026
04c475f
Fix floor symbol_index census: skip unindexed dotted prefixes.
Jul 15, 2026
3743a3b
Merge remote-tracking branch 'origin/main' into session/clever-stag-70
Jul 15, 2026
66c4da6
WIP: Grammar lane G1: qualified module projection resolve — value/typ…
Jul 15, 2026
37fae13
Fix v2 Conj resolve: only multi-segment QN paths use module projection.
Jul 15, 2026
7820904
Dissolve qualified_name_is_module_projection into length(path) > 1.
Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/v1/02_parse.dag
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ fn parse_type_body_after_eq(tokens: TokenStream, ctx: ParseContext, name: String
ItemResult { item: item, tokens: skip_newlines(tokens: rest.tokens), ctx: rest.ctx, err: none }
EatUnchanged { tokens: _ } =>
if tok_is_ident(tok: token_stream_first(stream: tokens)) {
let r = expect_ident(tokens: tokens)
let r = parse_dotted_ident(tokens: tokens)
if has_err(err: r.err) { return ItemResult { item: dummy, tokens: r.tokens, ctx: ctx, err: r.err } }
let first_name = r.name
let first_name_span = r.span
Expand Down Expand Up @@ -1519,8 +1519,16 @@ fn parse_type_expr(tokens: TokenStream, ctx: ParseContext) -> TypeResult {
}
}
Present { value: ShIdent } => {
let n = tok.value.text
finish_type_expr_from_name(tokens: token_stream_advance(stream: tokens, n: 1), ctx: ctx, type_name: n, start_span: span)
let r = parse_dotted_ident(tokens: tokens)
if has_err(err: r.err) {
return TypeResult {
type_expr: leaf_type_node(name: "", span: span),
tokens: r.tokens,
ctx: ctx,
err: r.err
}
}
finish_type_expr_from_name(tokens: r.tokens, ctx: ctx, type_name: r.name, start_span: r.span)
}
_ => TypeResult { type_expr: leaf_type_node(name: "", span: span), tokens: tokens, ctx: ctx, err: Present { value: parse_error(msg: "expected type expression", span: span) } }
}
Expand Down
32 changes: 30 additions & 2 deletions src/v1/04_env.dag
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type TypeEnv {
intern_table: InternTable
source_visible_names: Map<String, Bool>
global_bare: Map<String, GlobalBareLookupState>
symbol_index: SymbolIndex
}

type TypeBinding {
Expand All @@ -26,6 +27,8 @@ type TypeBinding {

data global_bare_fallback_invariant: String = "Corpus-wide bare-name census (namespace-resolution-design.md §8 PR-4): keyed on the bare declared name, one authority built once by build_global_bare_census over graph.modules before any module typechecks (order-independent — mirrors v2's symbol_index_global_bare, docs/plans/namespace-resolution-design.md §7.5). lookup_binding_by_name consults it only after str_bindings/ancestry_str_bindings/intern+bindings all miss, and only a GlobalBareUniqueBinding resolves; GlobalBareAmbiguousBinding stays Absent (fail-closed, never guesses — §5). This is what unblocks the src/v1 import strip: a bare reference that used to resolve via a deleted import chain still resolves here iff its name is globally unique in the corpus."

data qualified_module_projection_invariant: String = "Grammar lane G1: container.member module projection in type positions resolves via symbol_index_lookup on the full qualified path (module projection), not value field-access — v2 resolve: TypeNode Conj QN spines; v1 typecheck: lookup_binding_by_name after global_bare. build_symbol_index_census materializes declared-module paths once; lookup_qualified_module_projection runs only when the reference carries a dot (fail-closed on miss — never widens to field-access semantics)."

type GlobalBareLookupState
= GlobalBareUniqueBinding { binding: TypeBinding }
| GlobalBareAmbiguousBinding
Expand Down Expand Up @@ -371,10 +374,35 @@ fn lookup_binding_by_name(env: TypeEnv, name: String) -> TypeBinding? {
match intern_find(table: env.intern_table, s: name) {
Present { value: id } => match map_get(env.bindings, id) {
Present { value: binding } => Present { value: binding }
Absent => global_bare_lookup(env: env, name: name)
Absent => lookup_binding_after_global_bare(env: env, name: name)
}
Absent => lookup_binding_after_global_bare(env: env, name: name)
}
}
}
}

fn lookup_binding_after_global_bare(env: TypeEnv, name: String) -> TypeBinding? {
match global_bare_lookup(env: env, name: name) {
Present { value: binding } => Present { value: binding }
Absent => lookup_qualified_module_projection(env: env, name: name)
}
}

fn lookup_qualified_module_projection(env: TypeEnv, name: String) -> TypeBinding? {
match contains(name, ".") {
false => Absent
true =>
match symbol_index_lookup(index: env.symbol_index, qualified_name: name) {
Present { value: resolved } =>
Present {
value: TypeBinding {
name: name,
resolved: resolved,
provenance: SubValueUnknown
}
Absent => global_bare_lookup(env: env, name: name)
}
Absent => Absent
}
}
}
Expand Down
82 changes: 61 additions & 21 deletions src/v1/04_infer.dag

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/v1/04_resolve.dag
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,8 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemReso
source_indices: e.source_indices,
intern_table: e.intern_table,
source_visible_names: map_insert(e.source_visible_names, tp_name, true),
global_bare: e.global_bare
global_bare: e.global_bare,
symbol_index: e.symbol_index
}
)
let param_results = map(item.params, p => resolve_param(param: p, env: env, module_name: module_name))
Expand Down
4 changes: 2 additions & 2 deletions src/v1/05_emit.dag
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import v1.std.core {
CardOptional
}

import v1.compiler.infer_env { TypeEnv, TypeBinding, authored_name, GlobalBareLookupState }
import v1.compiler.infer_env { TypeEnv, TypeBinding, authored_name, GlobalBareLookupState, empty_symbol_index }
import std.induction { InductiveField, SubValueUnknown }
import v1.compiler.infer_types { resolved_type, child_type_node, emit_map_has, node_is_collection, node_is_keyed_collection, node_is_element_collection, normalize_access_type_node, for_each_element_type_node, is_unit_like, is_declared_container_alias_spelling }
import std.types { is_container_type, container_template_algebra }
Expand Down Expand Up @@ -270,7 +270,7 @@ fn emit_simple_string_interp(parts: List<StringPart>, target: RenderTarget, sour

fn empty_emit_scope() -> InferScope {
InferScope {
type_env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: empty_map(), intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map() },
type_env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: empty_map(), intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map(), symbol_index: empty_symbol_index() },
func_env: ResolvedFuncEnv { local: empty_map(), parents: [] },
locals: empty_map(),
match_bound_names: empty_map(),
Expand Down
12 changes: 6 additions & 6 deletions src/v1/05_emit_rust.dag
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ import v1.compiler.coercion { coerce_primitive_type, is_copy, lookup_checkpoint

import std.types { is_container_type, is_kernel_type }
import std.serialization { CoproductWireContract, VariantEncoding, VariantNaming }
import v1.compiler.infer_env { TypeEnv, TypeBinding, authored_name, lookup_type_by_name, lookup_type_for, GlobalBareLookupState }
import v1.compiler.infer_env { TypeEnv, TypeBinding, authored_name, lookup_type_by_name, lookup_type_for, GlobalBareLookupState, empty_symbol_index }
import v1.compiler.infer_types {
resolved_type, normalize_access_type_node, for_each_element_type_node,
child_type_node, emit_map_has,
Expand Down Expand Up @@ -154,7 +154,7 @@ fn render_rust_type(n: Node, shared_types: Set<String>, corpus_repr: RustCorpusR
match find_property(props: n.properties, prop_name: "__applied_type_args", source_indices: source_indices) {
Present { value: applied } =>
if applied.children |> count > 0 {
render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map() })
render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map(), symbol_index: empty_symbol_index() })
} else {
render_rust_type_without_applied_binding(n: n, shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices)
}
Expand All @@ -166,7 +166,7 @@ fn render_rust_type(n: Node, shared_types: Set<String>, corpus_repr: RustCorpusR
fn render_rust_type_without_applied_binding(n: Node, shared_types: Set<String>, corpus_repr: RustCorpusRepr, source_indices: Map<String, NewlineIndex>) -> String {
if is_host_text_carrier_type(n: n, source_indices: source_indices, corpus_repr: corpus_repr) { return rust_carrier_optional_wrap(n: n, rendered: "String") }
if n.connective == NoConnective && n.children |> count > 0 && !is_container_type(name: authored_name_at(source_indices: source_indices, node: n)) {
render_rust_applied_type_shared(n: n, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map() })
render_rust_applied_type_shared(n: n, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map(), symbol_index: empty_symbol_index() })
} else if node_is_set_collection(n: n, source_indices: source_indices) {
match n.children |> first {
Present { value: elem_child } =>
Expand Down Expand Up @@ -3435,10 +3435,10 @@ fn render_rust_type_with_applied_binding(n: Node, shared_types: Set<String>, cor
} else if set_contains(shared_types, outer_name) {
render_rust_shared_type_with_optional(n: n, type_name: outer_name, rendered: outer_name, shared_types: shared_types)
} else {
render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map() })
render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map(), symbol_index: empty_symbol_index() })
}
} else {
render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map() })
render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices, variant_to_enum: empty_map(), env: TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map(), symbol_index: empty_symbol_index() })
}
} else {
render_rust_type(n: n, shared_types: shared_types, corpus_repr: corpus_repr, source_indices: source_indices)
Expand Down Expand Up @@ -8328,7 +8328,7 @@ fn emit_test_file(module_name: String, projections: List<TestProjection>, corpus
}

fn rust_test_signature_comment(projection: TestProjection, corpus_repr: RustCorpusRepr) -> String {
let stub_env = TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: projection.source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map() }
let stub_env = TypeEnv { bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: projection.source_indices, intern_table: empty_intern_table(), source_visible_names: empty_map(), global_bare: empty_map(), symbol_index: empty_symbol_index() }
let params_str = projection.params
|> map(p => concat(param_node_name_at(n: p, source_indices: projection.source_indices), ": ", emit_rust_param_type(n: param_node_type_expr(n: p), generic_param_names: [], shared_types: empty_set(), corpus_repr: corpus_repr, source_indices: projection.source_indices, variant_to_enum: empty_map(), env: stub_env)))
|> join(separator: ", ")
Expand Down
2 changes: 2 additions & 0 deletions src/v1/compiler_tests_rust.dag
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,7 @@ fn ct_profile_reconcile_test() -> String {
" source_indices.clone(),\n",
" intern_table.clone(),\n",
" std::rc::Rc::new(HashMap::new()),\n",
" crate::v1_compiler_infer_env::empty_symbol_index(),\n",
" );\n",
" let env_elapsed = t_env.elapsed();\n",
" let rss_after_env = get_rss_bytes();\n",
Expand Down Expand Up @@ -1202,6 +1203,7 @@ fn ct_profile_reconcile_test() -> String {
" source_indices.clone(),\n",
" intern_table.clone(),\n",
" std::rc::Rc::new(HashMap::new()),\n",
" crate::v1_compiler_infer_env::empty_symbol_index(),\n",
" );\n",
" let full_elapsed = t_full.elapsed();\n",
" let rss_after = get_rss_bytes();\n",
Expand Down
6 changes: 6 additions & 0 deletions src/v1/stage0/src/bin/infer_semantics_witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ fn empty_type_env() -> Rc<TypeEnv> {
intern_table: v1_compiler::v1_std_core::empty_intern_table(),
source_visible_names: Rc::new(im_rc::HashMap::new()),
global_bare: Rc::new(im_rc::HashMap::new()),
symbol_index: v1_compiler::v1_compiler_infer_env::empty_symbol_index(),
})
}

Expand Down Expand Up @@ -1005,6 +1006,7 @@ fn optional_match_exhaustiveness_reports_missing_absent() {
intern_table: v1_compiler::v1_std_core::empty_intern_table(),
source_visible_names: Rc::new(im_rc::HashMap::new()),
global_bare: Rc::new(im_rc::HashMap::new()),
symbol_index: v1_compiler::v1_compiler_infer_env::empty_symbol_index(),
}),
zero_span(),
"test".to_string(),
Expand Down Expand Up @@ -1032,6 +1034,7 @@ fn optional_match_exhaustiveness_rejects_some_and_none() {
intern_table: v1_compiler::v1_std_core::empty_intern_table(),
source_visible_names: Rc::new(im_rc::HashMap::new()),
global_bare: Rc::new(im_rc::HashMap::new()),
symbol_index: v1_compiler::v1_compiler_infer_env::empty_symbol_index(),
}),
zero_span(),
"test".to_string(),
Expand Down Expand Up @@ -1059,6 +1062,7 @@ fn optional_match_exhaustiveness_accepts_present_and_absent() {
intern_table: v1_compiler::v1_std_core::empty_intern_table(),
source_visible_names: Rc::new(im_rc::HashMap::new()),
global_bare: Rc::new(im_rc::HashMap::new()),
symbol_index: v1_compiler::v1_compiler_infer_env::empty_symbol_index(),
}),
zero_span(),
"test".to_string(),
Expand Down Expand Up @@ -1123,6 +1127,7 @@ fn resolve_node_uses_node_name_for_lookup() {
intern_table: user_intern.table.clone(),
source_visible_names: Rc::new(im_rc::HashMap::new()),
global_bare: Rc::new(im_rc::HashMap::new()),
symbol_index: v1_compiler::v1_compiler_infer_env::empty_symbol_index(),
});

let result = resolve_node(node_ref, env, "test".to_string());
Expand Down Expand Up @@ -1642,6 +1647,7 @@ fn resolve_applied_generic_struct_expands_to_conj_for_field_lookup() {
intern_table: box_intern.table.clone(),
source_visible_names: Rc::new(im_rc::HashMap::new()),
global_bare: Rc::new(im_rc::HashMap::new()),
symbol_index: v1_compiler::v1_compiler_infer_env::empty_symbol_index(),
});

let box_nat = container_node("Box".to_string(), leaf_node("Nat".to_string()));
Expand Down
Loading
Loading