diff --git a/dag/gunbc/host_effect_realize.dag b/dag/gunbc/host_effect_realize.dag index 0cecbf6bb56..d313d60b659 100644 --- a/dag/gunbc/host_effect_realize.dag +++ b/dag/gunbc/host_effect_realize.dag @@ -2639,6 +2639,10 @@ fn srv3_toolchain_receipt(observations: List) -> String { ) } +fn srv3_observation_verdict(observation: Srv3ToolObservation) -> Srv3HostPredicate { + observation.verdict +} + fn srv3_realize_os_install_actuator_toolchain_ensure_body( transport: HostEffectTransport, effect_intent: HostEffectIntent, @@ -2653,7 +2657,7 @@ fn srv3_realize_os_install_actuator_toolchain_ensure_body( }, ) let verdict = srv3_summarize_independent_observations( - steps: list_map(xs: observations, f: fn(o) { o.verdict }), + steps: list_map(xs: observations, f: fn(o) { srv3_observation_verdict(observation: o) }), ) let stdout = srv3_toolchain_receipt(observations: observations) match verdict { diff --git a/dag/std/primitive_projection.dag b/dag/std/primitive_projection.dag index 2624d20fce8..5d45d3bf9e5 100644 --- a/dag/std/primitive_projection.dag +++ b/dag/std/primitive_projection.dag @@ -5,10 +5,20 @@ import std.types { List, NonEmptyStr, String } data primitive_projection_seed_boundary_note: String = "The declaration-to-primitive projection is a seed-consumed substrate authority, so its import closure stops at std.decl_ref/std.types and never reaches a target roster or v2 module. This module is a strict relocation of the projection identity, fidelity, roster, and exact-declaration query formerly declared inside std.primitive_identity. std.primitive_identity consumes this authority for its census and total disposed/undisposed answer; the stage0 resolver consumes the same exact-declaration query. Required regen is the mechanical wall: src/v1 importing the former home reached gunbc.v1_interpreter_primitive_surface and then v2.std.qualified_name, which the src/v1 + dag bootstrap closure correctly refuses. The refusal is the seed-safety boundary working, not build friction." -type PrimitiveIdentity { slug: NonEmptyStr } +data primitive_identity_slug_prefix: String = "primitive." + +type PrimitiveIdentity sole_constructor { slug: NonEmptyStr } + +// The seal governs .dag construction; generated Rust mirrors remain ordinary +// structs and therefore are not an end-to-end construction wall. fn primitive_identity_slug(name: String) -> PrimitiveIdentity { - PrimitiveIdentity { slug: concat("primitive.", name) as NonEmptyStr } + PrimitiveIdentity { slug: concat(primitive_identity_slug_prefix, name) as NonEmptyStr } +} + +fn primitive_identity_runtime_name(identity: PrimitiveIdentity) -> String { + let slug = identity.slug as String + substring(s: slug, start: string_length(s: primitive_identity_slug_prefix), end: string_length(s: slug)) } data primitive_projection_identity_key_note: String = "The projection is keyed on std.decl_ref DeclarationRef, which is the namespace layer's own identity for a declaration (DESIGN section 3: namespace supplies declaration identity, this carrier supplies semantic primitive identity). No new identity type is minted here. The alternative shape considered and refused was a per-declaration marker row beside each fn: it is a second representation scattered across modules rather than one authority, it keys on a bare name inside a module scope so two same-named declarations collapse into one, and it has no room for a fidelity distinction. Module qualification answers the second; this single carrier answers the first; ProjectionFidelity answers the third." diff --git a/dag/test/claim/resolved_call_emission_identity_witness_test.dag b/dag/test/claim/resolved_call_emission_identity_witness_test.dag new file mode 100644 index 00000000000..61dd4e7ad3f --- /dev/null +++ b/dag/test/claim/resolved_call_emission_identity_witness_test.dag @@ -0,0 +1,79 @@ +module test.claim.resolved_call_emission_identity_witness_test + +import v2.std.live_tree { LiveTreeDisposition, ReadsLiveTree } + +data live_tree_disposition: LiveTreeDisposition = ReadsLiveTree + +data resolved_call_emission_identity_witness_note: String = "Permanent regression control for post-resolution callable identity at Rust emission. The source resolver chooses once; 05_emit_rust consumes the recorded RuntimePrimitiveCall or exact SourceDeclarationCall and never asks rt_functions by leaf spelling. The positive trap is the real two-String substring primitive, which must still lower to v1_rt::contains. The empty_map arm proves an exact declaration carrying the existing primitive projection remains host-lowered. The contains and map_get arms prove ordinary and DivergentProjection declarations retain their source identities; together they reproduce the 28-block board mechanism across its two live names. The local same-name arm proves an unrelated declaration cannot become a primitive merely because its leaf collides. map_insert is deliberately absent: v2.std.collection currently carries both map_insert_host_binding and a closure-backed modeled body, while no authority decides which one owns calls; this repair consumes the existing projection roster and does not reclassify that unresolved specimen. dissolve-on: never -- emission may change target spelling, but it may never reintroduce name lookup after source resolution." + +fn w_two_string_substring_contains_stays_runtime_bound() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.runtime_substring_contains_probe\nimport std.types { Bool, String }\nfn probe(s: String, sub: String) -> Bool { contains(s, sub) }\n", + "src/test_claim_runtime_substring_contains_probe.rs", + ["v1_rt::contains("], + [] + ) +} + +fn w_primitive_bound_empty_map_stays_runtime_bound() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.runtime_empty_map_probe\nimport std.types { Int, String, Map }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.collection { empty_map }\nfn probe() -> Map { empty_map() }\n", + "src/test_claim_runtime_empty_map_probe.rs", + ["v1_rt::rc_empty_map"], + ["v2_std_collection::empty_map("] + ) +} + +fn w_imported_generic_contains_keeps_declared_identity() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.declared_contains_probe\nimport std.types { Int, Bool }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.algebra { FreeMonoid, contains }\nfn int_eq(left: Int, right: Int) -> Bool { left == right }\nfn probe(xs: FreeMonoid) -> Bool { contains(xs: xs, item: 1, eq: int_eq) }\n", + "src/test_claim_declared_contains_probe.rs", + ["crate::v2_std_algebra::contains("], + ["v1_rt::contains("] + ) +} + +fn w_divergent_map_get_keeps_declared_outcome_identity() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.declared_map_get_probe\nimport std.types { Int, String, Map }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.collection { map_get }\nimport v2.std.diagnostic { Outcome }\nimport v2.std.optional { Optional }\nfn probe(m: Map) -> Outcome> { map_get(m: m, key: \"key\") }\n", + "src/test_claim_declared_map_get_probe.rs", + ["crate::v2_std_collection::map_get("], + ["v1_rt::map_get("] + ) +} + +fn w_unrelated_same_named_declaration_never_becomes_runtime_primitive() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.local_contains_probe\nimport std.types { Int }\nfn contains(left: Int, right: Int, third: Int) -> Int { left + right + third }\nfn probe() -> Int { contains(1, 2, 3) }\n", + "src/test_claim_local_contains_probe.rs", + ["contains(1, 2, 3)"], + ["v1_rt::contains("] + ) +} + +fn w_product_data_call_initializer_reaches_typed_call_emission() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.product_data_call_probe\nimport std.types { String }\ntype ProbeIdentity { slug: String }\nfn make_probe_identity() -> ProbeIdentity { ProbeIdentity { slug: \"probe\" } }\ndata probe_identity: ProbeIdentity = make_probe_identity()\n", + "src/test_claim_product_data_call_probe.rs", + ["make_probe_identity()"], + ["unsupported mock expression"] + ) +} + +fn w_resolved_signature_owner_selects_runtime_primitive() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.resolved_signature_owner_probe\nimport std.types { Int, String, Map }\nfn probe(m: Map) -> Map { map_insert(m, \"key\", 1) }\n", + "src/test_claim_resolved_signature_owner_probe.rs", + ["v1_rt::rc_map_insert("], + ["call target identity was not established"] + ) +} + +fn w_selective_function_import_admits_named_function() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.selective_function_import_green\nimport std.types { Int }\nimport test.fixture.function_import_surface_provider { imported_fn }\nfn probe() -> Int { imported_fn(1) }\n", + "src/test_claim_selective_function_import_green.rs", + ["function_import_surface_provider::imported_fn(1)"], + [] + ) +} diff --git a/dag/test/claim/serving_privilege_derivation_witness_test.dag b/dag/test/claim/serving_privilege_derivation_witness_test.dag index 00b97e06ba7..44dc95f8cfe 100644 --- a/dag/test/claim/serving_privilege_derivation_witness_test.dag +++ b/dag/test/claim/serving_privilege_derivation_witness_test.dag @@ -1,6 +1,7 @@ module test.claim.serving_privilege_derivation_witness_test import std.types { String, Bool, List, NonEmptyStr, Int } +import std.algebra { Empty } import std.content_hash { content_hash_of_value } import product.placement_supply { HostIdentity } import gunbc.spark.serving_realization { diff --git a/dag/test/claim/sole_constructor_completeness_audit_probe.dag b/dag/test/claim/sole_constructor_completeness_audit_probe.dag index 9c9b2bb2a08..1e633405f60 100644 --- a/dag/test/claim/sole_constructor_completeness_audit_probe.dag +++ b/dag/test/claim/sole_constructor_completeness_audit_probe.dag @@ -11,6 +11,8 @@ import std.types { String, Bool, Int } import v2.std.live_tree { LiveTreeDisposition, ReadsLiveTree } import std.interval { closed_interval, IntervalConstruction, IntervalReady, IntervalRefused } +// Virtual sources resolve imports against the live repository tree; this probe +// is therefore authoring-time evidence until a live-tree execution home exists. data live_tree_disposition: LiveTreeDisposition = ReadsLiveTree fn census_of(source: String) -> CompileDiagnosticCensus { @@ -125,6 +127,20 @@ test fn f9_generic_carrier_green_control_clean() -> Bool { violation_count(source: f9_generic_green_source, wanted: "SoleConstructorViolation") == 0 } +// PrimitiveIdentity seal controls: forging the cross-module record must refuse, +// while the sole constructor remains an accepted mint path. +data primitive_identity_forge_source: String = "module probe_primitive_identity_forge\nimport std.primitive_projection { PrimitiveIdentity }\nfn forged() -> PrimitiveIdentity { PrimitiveIdentity { slug: \"primitive.fake\" } }\n" + +test fn primitive_identity_cross_module_forge_refuses() -> Bool { + violation_count(source: primitive_identity_forge_source, wanted: "SoleConstructorViolation") >= 1 +} + +data primitive_identity_mint_source: String = "module probe_primitive_identity_mint\nimport std.primitive_projection { PrimitiveIdentity, primitive_identity_slug }\nfn legal() -> PrimitiveIdentity { primitive_identity_slug(name: \"fake\") }\n" + +test fn primitive_identity_mint_control_clean() -> Bool { + violation_count(source: primitive_identity_mint_source, wanted: "SoleConstructorViolation") == 0 +} + // --------------------------------------------------------------------------- // Order-dependence probe: two modules declare a bare-name-identical type // `DupShape`, one sole_constructor, one not (test.fixture.sole_constructor_order_probe diff --git a/dag/test/claim/spark_bootstrap_provision_witness_test.dag b/dag/test/claim/spark_bootstrap_provision_witness_test.dag index e05b0a5eff6..4257c858678 100644 --- a/dag/test/claim/spark_bootstrap_provision_witness_test.dag +++ b/dag/test/claim/spark_bootstrap_provision_witness_test.dag @@ -1,5 +1,6 @@ module test.claim.spark_bootstrap_provision_witness +import std.types { list_length } // Adding ANY explicit import scopes this witness's resolution, so the subject module -- previously // reached by bare reference through pool coincidence -- must now be named too. That is the correct // direction (a witness should carry its own edge to its subject), but the transition is abrupt: @@ -561,7 +562,7 @@ test fn spark_reported_principal_cannot_actuate() -> Bool { test fn spark_effective_access_is_only_partially_observed() -> Bool { match spark_effective_access_standing() { EffectiveAccessPartiallyObserved { positively_observed: p, requested_but_not_returned: r, overbreadth_unobserved_cause: _ } => - p.length() == 1 && r.length() > 0 + list_length(items: p) == 1 && list_length(items: r) > 0 EffectiveAccessExact { observed_cells: _ } => false EffectiveAccessOverbroad { extra_cells: _ } => false EffectiveAccessUnobserved { cause: _ } => false diff --git a/dag/test/fixture/function_import_surface_provider.dag b/dag/test/fixture/function_import_surface_provider.dag new file mode 100644 index 00000000000..d195034077f --- /dev/null +++ b/dag/test/fixture/function_import_surface_provider.dag @@ -0,0 +1,7 @@ +module test.fixture.function_import_surface_provider + +import std.types { Int } + +fn imported_fn(value: Int) -> Int { value } + +fn hidden_fn(value: Int) -> Int { value + 1 } diff --git a/docs/briefs/resolver_pool_fallback_census_2026-08-24.md b/docs/briefs/resolver_pool_fallback_census_2026-08-24.md index eecebe277b8..7e49b40d426 100644 --- a/docs/briefs/resolver_pool_fallback_census_2026-08-24.md +++ b/docs/briefs/resolver_pool_fallback_census_2026-08-24.md @@ -1,31 +1,37 @@ -# Self-host bootstrap contamination receipt (2026-08-24) +# Resolver pool-fallback census (2026-08-24) -PR #9075 initially produced 361 floor diagnostics and 71 regeneration -refusals. Those measurements are withdrawn: they came from a compiler seeded -from an earlier state of the same PR, not from a known-good compiler. +The required-floor run on PR #9075 exposed 361 diagnostic lines after the +emission mask was removed. These are not 361 independent defects. Symptom +bucketization yields two root families: -The discriminating experiment used one dispatch and identical merged sources: +- No definer in the scoped closure: `split` (26), `first` (38), `skip` (10), + `length` (10), `trim` (8), receiver `split` (8), and indexing (8). +- Wrong carrier selected through pool fallback: `Present`/`Absent` variants + on `FreeMonoid` (18 each), `Empty`/`Cons` exhaustiveness (46), incompatible + `FreeMonoid`/`List`/`String` branches, and generic-field fallout. -- Seed: `claim_executor` built from merge-base `bd84f6696`. -- Subject: merged PR sources at `8913ff5`. -- Result: v2 compilation completed with zero hard diagnostics; regeneration - planned/executed 136/136, with only generated-surface drift - (`first_generation_equal=false`, `declared_divergent=1`). +The second family matches the diagnosed alias: `std.types` declares +`type List = FreeMonoid` (and analogous `Map`/`Set` aliases) +and records the same mapping in `container_template_alias_rows`. A bare name +missing scoped visibility can therefore bind a plausible but wrong carrier +from the pool. A prior `Map` realization defect produced `PartialFunction` in +kernel `Map` type positions through this same alias family. Counts are symptom +buckets, not per-site root proofs; resolver provenance is required for exact +attribution. -The earlier 71 refusals were artifacts of a contaminated self-hosting seed. A -source-only diff cannot distinguish “the source is wrong” from “the compiler -that produced its mirror is wrong”; a known-good seed on the same subject is -the required control. Do not use the withdrawn 361-line taxonomy as evidence -about resolver behavior. +There are two lookup layers and their bounds must not be conflated. The +file-closure `pool_bare_census` is root-scoped and has a measured population +of 733 cross-root candidates (510 `src/v1 -> dag`, 223 `dag -> src/v1`). The +function-signature fallback (`func_sig_from_global_bare` and +`global_bare_callable_node`) has no root parameter and reads `symbol_index.global_bare`; +the 733 bound is therefore reported only for the file-closure path, not +transferred to this separate layer. Root A's six representative names +(`split`, `first`, `skip`, `length`, `trim`, and `join`) are all algebra method +templates. An explicit law in `04_infer.dag` gates every algebra-template name +out of the census fallback, so these symptoms cannot be attributed to the +signature fallback. Their downstream relationship to carrier/profile lookup +remains a separate measurement, not asserted by this census. -This control rule is scoped to cross-binary comparisons: if each tree is -measured by a different compiler, the compiler moved with the subject and the -attribution is invalid. Paired arms measured by the same binary retain their -delta even if that binary is itself imperfect; state the result as behavior in -that compiler, not as a universal gunbc claim. This receipt makes no claim -about the shipped compiler beyond the exact seed revision named above. - -This receipt does not invalidate independent observations about pool fallback, -the `std.types` `List = FreeMonoid` alias, or #9083's stripped-header finding; -those require their own provenance. It also does not authorize installing the -drifted candidate mirror; drift remains a separate fixed-point question. +This census is evidence produced by the floor after the emission leaf-name +mask was removed. It does not authorize consumer repairs in PR #9075. The +upstream fix belongs to the namespace/admission work (including #9113). diff --git a/src/v1/00_core.dag b/src/v1/00_core.dag index 680d1041eb1..3ac61b9d0df 100644 --- a/src/v1/00_core.dag +++ b/src/v1/00_core.dag @@ -91,9 +91,14 @@ type VarBindingKind | VariantValueBinding { parent_enum: String } | MatchBoundBinding +type CallTargetIdentity + = RuntimePrimitiveCall { primitive_name: String } + | SourceDeclarationCall { owner_module_path: String, decl_name: String } + | CallableTargetUndetermined + type CallSemantics - = PlainCallSemantics - | LookupCallSemantics + = PlainCallSemantics { target: CallTargetIdentity } + | LookupCallSemantics { target: CallTargetIdentity } | FunctionValueCallSemantics type MethodSemantics diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 21edb37cbcf..3404fc3c5e2 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -47,6 +47,7 @@ import v1.std.core { FieldAccessStyle, StoredField, EnumAccessor, OptionalUnwrap, TupleFirst, TupleSecond, FieldValueShape, PlainValue, OptionalValue, FieldSummary, VarBindingKind, LocalValueBinding, FunctionValueBinding, VariantValueBinding, MatchBoundBinding, + CallTargetIdentity, RuntimePrimitiveCall, SourceDeclarationCall, CallableTargetUndetermined, CallSemantics, PlainCallSemantics, LookupCallSemantics, FunctionValueCallSemantics, MethodSemantics, PlainMethodSemantics, AlgebraMethodSemantics, ServiceMethodSemantics, @@ -198,6 +199,11 @@ import v1.compiler.infer_access { check_index_access_node, check_slice_access_node } import std.dissolution { DissolutionCondition, unbound_dissolution, dissolution_description } +import std.decl_ref { decl_ref } +import std.primitive_projection { + primitive_projection_row_for_declaration, + HostRealizedSeam, ModeledProjection, DivergentProjection +} fn is_witness_type_name(name: String) -> Bool { name == "Witness" || name == "witness" @@ -3719,12 +3725,12 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu } Absent => match lookup_func_sig(func_env: scope.func_env, type_env: scope.type_env, name: name) { - FuncSigResolved { sig: fsig } => + FuncSigResolved { sig: fsig, owner_module_path: sig_owner } => match (fsig.params |> count) == 0 { true => ok_infer(texpr: make_named_expr_node( name: name, - expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: name, sig_lookup: FuncSigResolved { sig: fsig, owner_module_path: sig_owner }) } }, descent_evidence: none }, children: [], inferred: Present { value: Resolved { node: fsig.inferred } }, span: span, @@ -4021,7 +4027,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu ) InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: resolved_type } }, span: span, @@ -4123,12 +4129,13 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu } } else if !callee_is_body_binding && func_name == "empty_map" { let bare_m = bare_map_node() + let empty_map_call_semantics = Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map" } } } match expected { Present { value: exp } => if node_is_keyed_collection(n: exp, source_indices: scope.type_env.source_indices) { InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: empty_map_call_semantics, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: exp } }, span: span, @@ -4142,7 +4149,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Present { value: map_t } => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: empty_map_call_semantics, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: map_t } }, span: span, @@ -4153,7 +4160,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Absent => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: empty_map_call_semantics, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: CompilerError { message: "empty_map(): Map kernel container profile missing (compiler misconfigured)", span: span } }, span: span, @@ -4168,7 +4175,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Present { value: map_t } => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: empty_map_call_semantics, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: map_t } }, span: span, @@ -4179,7 +4186,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Absent => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: empty_map_call_semantics, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: CompilerError { message: "empty_map(): Map kernel container profile missing (compiler misconfigured)", span: span } }, span: span, @@ -4196,7 +4203,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu if node_is_set_collection(n: exp, source_indices: scope.type_env.source_indices) { InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: exp } }, span: span, @@ -4210,7 +4217,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Present { value: set_t } => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: set_t } }, span: span, @@ -4221,7 +4228,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Absent => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: CompilerError { message: "empty_set(): Set kernel container profile missing (compiler misconfigured)", span: span } }, span: span, @@ -4236,7 +4243,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Present { value: set_t } => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: set_t } }, span: span, @@ -4247,7 +4254,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Absent => InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: CompilerError { message: "empty_set(): Set kernel container profile missing (compiler misconfigured)", span: span } }, span: span, @@ -4261,9 +4268,9 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu let tier2b = infer_tier2b_builtin_with_kernel_diags(func_name: func_name, typed_args: typed_args, scope: scope, span: span) let bt = tier2b.bt let call_semantics = if func_name == "lookup" { - Present { value: LookupCallSemantics } + Present { value: LookupCallSemantics { target: RuntimePrimitiveCall { primitive_name: func_name } } } } else { - Present { value: PlainCallSemantics } + Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } } } InferResult { typed: make_named_expr_node( @@ -4293,7 +4300,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu } InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: if callee_is_body_binding { FunctionValueCallSemantics } else { PlainCallSemantics } }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: if callee_is_body_binding { FunctionValueCallSemantics } else { PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: resolved_type } }, span: span, @@ -4338,7 +4345,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu } InferResult { typed: make_named_expr_node( - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: resolved_plain_call_target(scope: scope, func_name: func_name, sig_lookup: call_sig_lookup) } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: resolved_type } }, span: span, @@ -4371,7 +4378,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Present { value: infer_expr( texpr: make_named_expr_node( name: dotted, - expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics }, descent_evidence: none }, + expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: CallableTargetUndetermined } }, descent_evidence: none }, children: mc_args, inferred: none, span: span, @@ -5186,6 +5193,51 @@ fn needs_alias_field_expansion(n: Node, env: TypeEnv) -> Bool { data call_locals_shadow_note: String = "Body-scope binders shadow the fn-sig lookup in the ExprCall arm (nearest-first precedence: body locals > module fns > census global_bare). Without this gate a corpus-unique census homonym out-precedes a `let` callee: refinement.dag's `let classify = by.classify; match classify(base)` typed the scrutinee as a v2 lens test module's `fn classify -> Optional`, refusing the match arms against the wrong enum (variant not found in Optional + non-exhaustive missing Absent/Present). The gate reads body_locals — the strict body-grain subset (let / match pattern / fn+lambda params) of scope.locals — because the module context pre-seeds locals with variant and service census bindings that must NOT eclipse fn sigs (an imported 0-arg fn would lose its sig to its own census row: html_fragment.dag's html_markup_medium() typed as an unresolved primitive). Absent sends the call down the local-callable path exactly as the pre-census seed did. Companion precedence law lives in func_sig_from_global_bare (infer_lookup): the census fallback never serves an algebra method-template name (filter/any/contains/…) — a whole-pool census entry for the UNLOADED v2.std.algebra must not preempt the known-method bridge (main-parity: on main such free calls type through the bridge; a census-served sig typed filter(xs, f) as a plain call to a never-loaded module and the runtime died NoSuchFunction)." +data resolved_call_target_identity_note: String = "A call is resolved once, where its lexical scope is available, and emission consumes that exact result. RuntimePrimitiveCall is produced only by builtin resolution or when std.primitive_projection says THIS exact declaration is a HostRealizedSeam/ModeledProjection of the primitive. SourceDeclarationCall is retained for ordinary declarations and for DivergentProjection (v2.std.collection map_get is the canonical divergent row). The authored leaf spelling never participates in target selection after this point. CallableTargetUndetermined is a refusal-bearing residue, not permission for emission to retry name lookup. This closes the authority-substitution class in which v2.std.algebra contains resolved correctly but 05_emit_rust re-decided it as the unrelated two-String v1_rt substring primitive. The same identity is consumed by free-call bridge selection, by-reference lowering, and result wrapping; source_visible_names would only let emission repeat resolution and is deliberately not the mechanism." + +data empty_map_call_target_proof_note: String = "empty_map is intentionally absent from builtin_function_registry because its return type comes from the expected Map shape. Reaching the dedicated empty_map inference branch is therefore both the keyed-container type proof and the runtime-primitive target proof; that branch records RuntimePrimitiveCall directly instead of asking the generic signature lookup to reconstruct an identity it does not own." + +fn resolved_plain_call_target(scope: InferScope, func_name: String, sig_lookup: FuncSigLookup) -> CallTargetIdentity { + match sig_lookup { + FuncSigResolved { sig: _, owner_module_path: owner_module_path } => + resolved_declaration_call_target(owner_module_path: owner_module_path, decl_name: qualified_last_segment(name: func_name), func_name: func_name) + FuncSigUnresolved => + if infer_builtin_call_type(name: func_name) != none { + RuntimePrimitiveCall { primitive_name: func_name } + } else { + CallableTargetUndetermined + } + FuncSigAmbiguous { candidates: _ } => CallableTargetUndetermined + } +} + +fn resolved_call_target_from_declaration_lookup(declaration_lookup: ConstructorDeclarationLookup, func_name: String) -> CallTargetIdentity { + match declaration_lookup { + ExactConstructorDeclaration { identity: identity, declaration: _ } => + resolved_declaration_call_target(owner_module_path: identity.owner_module_path, decl_name: identity.decl_name, func_name: func_name) + AdmissionBearingDeclarationUnavailable { identity: identity, cause: _ } => + resolved_declaration_call_target(owner_module_path: identity.owner_module_path, decl_name: identity.decl_name, func_name: func_name) + NotAdmissionBearingReference {} => + if infer_builtin_call_type(name: func_name) != none { + RuntimePrimitiveCall { primitive_name: func_name } + } else { + CallableTargetUndetermined + } + } +} + +fn resolved_declaration_call_target(owner_module_path: String, decl_name: String, func_name: String) -> CallTargetIdentity { + match primitive_projection_row_for_declaration(declaration: decl_ref(module_path: owner_module_path, decl_name: decl_name)) { + Present { value: row } => + match row.fidelity { + HostRealizedSeam => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive) } + ModeledProjection => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive) } + DivergentProjection { divergence: _ } => SourceDeclarationCall { owner_module_path: owner_module_path, decl_name: decl_name } + } + Absent => SourceDeclarationCall { owner_module_path: owner_module_path, decl_name: decl_name } + } +} + data peel_alias_fixpoint_guard_note: String = "Termination (§4 boundedness) and diagnostic completeness (§5): peel iterates resolve_node toward a groundable form; a node that resolves to ITSELF (a self-resolving generic constructor such as List — NoConnective, children>0, inferred=none, unbound-or-identity under resolve) is a resolve FIXED POINT, the expansion frontier. Without the once==n check the recurse arm loops forever on that shape (measured: one peel call spun 3M+ iterations / 396M resolve calls on the #6640 total-census tree, witness test.claim.bmc_bootstrap_provision_witness, fp trace c1f861179e→d33138c3f8→256ee7d351 repeating — progress-then-self-loop, no >1-cycle, so consecutive-equal suffices; a memo cannot terminate it, only make each spin fast). The fixed-point/non-alias arm is a legitimate speculative probe miss ONLY when resolve_node returns no diagnostics. The old Node return projected .resolved and discarded .diagnostics, making that quiet miss byte-identical to a real resolver refusal and zeroing the refusal's frequency before CompileResult, compile-clean, and the diagnostic census could observe it. The peel now returns the existing NodeResolveResult authority and accumulates every hop's diagnostics. ExprFieldAccess and record-literal alias field discovery are judgment-producing callers and must carry those diagnostics. Variant-membership and emit-shaping callers are metadata-only probes: they may inspect .resolved but do not admit an executable artifact or own a diagnostic ledger, so making them emit would turn speculative shape lookup into a false red. No second peel outcome vocabulary is minted beside the resolver's own typed carrier." fn peel_alias_once_for_field_access(n: Node, env: TypeEnv, module_name: String) -> NodeResolveResult { @@ -10126,6 +10178,68 @@ fn build_imported_variants(resolved_imports: List, parent_index: ) } +fn selective_func_env_view(env: ResolvedFuncEnv, names: List) -> ResolvedFuncEnv { + let selected = fold(names, init: empty_map(), f: (acc, name) => + match map_get(env.local, name) { + Present { value: sig } => map_insert(acc, name, sig) + Absent => acc + } + ) + ResolvedFuncEnv { name: env.name, local: selected, parents: [] } +} + +fn func_env_views_for_import(parent: ResolvedFuncEnv, is_all: Bool, specific_names: List) -> List { + if is_all { [parent] } + else { + concat([parent], parent.parents) + |> map(env => selective_func_env_view(env: env, names: specific_names)) + } +} + +type FuncEnvViewMerge { + by_owner: Map + owner_order: List +} + +fn merge_func_sig_maps(base: Map, incoming: Map) -> Map { + fold(map_keys(incoming), init: base, f: (acc, name) => + match map_get(incoming, name) { + Present { value: sig } => map_insert(acc, name, sig) + Absent => acc + } + ) +} + +// Separate direct imports can reach the same real owner through different +// flattened closures. Union their admitted locals before owner deduplication; +// otherwise an empty selective view can suppress an explicitly imported name. +fn merge_func_env_views_by_owner(views: List) -> List { + let merged = fold(views, init: FuncEnvViewMerge { by_owner: empty_map(), owner_order: [] }, f: (acc, view) => + match map_get(acc.by_owner, view.name) { + Present { value: existing } => + FuncEnvViewMerge { + by_owner: map_insert( + acc.by_owner, + view.name, + ResolvedFuncEnv { name: view.name, local: merge_func_sig_maps(base: existing.local, incoming: view.local), parents: [] } + ), + owner_order: acc.owner_order + } + Absent => + FuncEnvViewMerge { + by_owner: map_insert(acc.by_owner, view.name, view), + owner_order: list_push(acc.owner_order, view.name) + } + } + ) + merged.owner_order |> flat_map(owner => + match map_get(merged.by_owner, owner) { + Present { value: env } => [env] + Absent => [] + } + ) +} + fn build_module_context(contributions: List, parent_index: Map, variant_surfaces: Map, @@ -10192,12 +10306,12 @@ fn build_module_context(contributions: List, svc_registry: map_merge(census_scope.svc_registry, local.svc_registry), svc_locals: map_merge(census_scope.svc_locals, local.svc_locals) ) - let parent_envs = flat_map(resolved_imports, imp => + let parent_envs = merge_func_env_views_by_owner(flat_map(resolved_imports, imp => match map_get(parent_index, imp.module_path) { - Present { value: typed_parent } => [typed_parent.func_env] + Present { value: typed_parent } => func_env_views_for_import(parent: typed_parent.func_env, is_all: imp.is_all, specific_names: imp.specific_names) Absent => [] } - ) + )) let resolve_result = resolve_func_sigs( declared_sigs: local.func_sigs, parent_envs: parent_envs, @@ -10966,13 +11080,17 @@ fn rewire_func_env_parent_links(modules: List, source_indices: Map< map_insert(acc, authored_name_at(source_indices: source_indices, node: m.module), m) ) map(modules, m => - let parents = flat_map(module_imports(n: m.module), imp => + let parents = merge_func_env_views_by_owner(flat_map(module_imports(n: m.module), imp => let path = import_module_path_at(imp: imp, source_indices: source_indices) match map_get(index, path) { - Present { value: parent } => [parent.func_env] + Present { value: parent } => func_env_views_for_import( + parent: parent.func_env, + is_all: import_is_all(n: imp), + specific_names: import_specific_names_at(n: imp, source_indices: source_indices) + ) Absent => [] } - ) + )) TypedModule { module: m.module, items: m.items, diff --git a/src/v1/04_lookup.dag b/src/v1/04_lookup.dag index fad222fea98..50432fe93c6 100644 --- a/src/v1/04_lookup.dag +++ b/src/v1/04_lookup.dag @@ -85,7 +85,7 @@ fn lookup_func_sig(func_env: ResolvedFuncEnv, type_env: TypeEnv, name: String) - FuncSigUnresolved } else { match lookup_resolved_sig(env: func_env, name: name) { - FuncSigResolved { sig: sig } => FuncSigResolved { sig: sig } + FuncSigResolved { sig: sig, owner_module_path: owner } => FuncSigResolved { sig: sig, owner_module_path: owner } FuncSigAmbiguous { candidates: cands } => FuncSigAmbiguous { candidates: cands } FuncSigUnresolved => func_sig_from_global_bare(type_env: type_env, name: name) } @@ -94,7 +94,7 @@ fn lookup_func_sig(func_env: ResolvedFuncEnv, type_env: TypeEnv, name: String) - fn func_sig_if_resolved(lookup: FuncSigLookup) -> ResolvedFuncSig? { match lookup { - FuncSigResolved { sig: sig } => Present { value: sig } + FuncSigResolved { sig: sig, owner_module_path: _ } => Present { value: sig } FuncSigUnresolved => Absent FuncSigAmbiguous { candidates: _ } => Absent } @@ -272,7 +272,7 @@ fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> FuncSigLookup { is_async: false, output_provenance: [], variant_provenance: empty_map() - } } + }, owner_module_path: bd.owner_module_path } } else { let qualified_return = qualify_borrowed_type_names(n: raw_return, owner_module_path: bd.owner_module_path, env: type_env, excluded: excluded) FuncSigResolved { sig: ResolvedFuncSig { @@ -282,7 +282,7 @@ fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> FuncSigLookup { is_async: false, output_provenance: [], variant_provenance: empty_map() - } } + }, owner_module_path: bd.owner_module_path } } } Absent => FuncSigUnresolved diff --git a/src/v1/04_sigs.dag b/src/v1/04_sigs.dag index 0282664ae77..e972eb56feb 100644 --- a/src/v1/04_sigs.dag +++ b/src/v1/04_sigs.dag @@ -73,10 +73,10 @@ type ParentSigScan { first_parent: String? } -data func_sig_lookup_outcome_note: String = "namespace-resolution-design.md 13 / 8 step 1, fn path: ResolvedFuncSig? overloaded Absent as 'keep looking' (the census fallback fires on it), so a refusal had nowhere to go — the first-hit over func_env.parents was the fn silent-pick class (fn_parent_first_hit) with NO refusal arm at all. FuncSigLookup is the 3-state outcome: FuncSigResolved binds, FuncSigUnresolved means genuinely-no-sig (census fallback may still run), FuncSigAmbiguous carries the full candidate list and REFUSES — it never falls through to a fallback. Under ImportScoped (host bracket false) the first-hit behavior remains until the downstream production flip; under NamespaceOnlyY exactly-one match across the flat parent closure resolves, two-plus refuses through module_path_owner_binding_decide. Own-module local hit stays first on both arms." +data func_sig_lookup_outcome_note: String = "namespace-resolution-design.md 13 / 8 step 1, fn path: ResolvedFuncSig? overloaded Absent as 'keep looking' (the census fallback fires on it), so a refusal had nowhere to go — the first-hit over func_env.parents was the fn silent-pick class (fn_parent_first_hit) with NO refusal arm at all. FuncSigLookup is the 3-state outcome: FuncSigResolved binds the signature AND its exact owner module, FuncSigUnresolved means genuinely-no-sig (census fallback may still run), FuncSigAmbiguous carries the full candidate list and REFUSES — it never falls through to a fallback. The owner is part of resolution, not reconstructible from admission lookup: emission target identity consumes it directly after inference. Under ImportScoped (host bracket false) the first-hit behavior remains until the downstream production flip; under NamespaceOnlyY exactly-one match across the flat parent closure resolves, two-plus refuses through module_path_owner_binding_decide. Own-module local hit stays first on both arms." type FuncSigLookup - = FuncSigResolved { sig: ResolvedFuncSig } + = FuncSigResolved { sig: ResolvedFuncSig, owner_module_path: String } | FuncSigUnresolved | FuncSigAmbiguous { candidates: List } @@ -98,9 +98,9 @@ fn lookup_resolved_sig_unique_across_parents(env: ResolvedFuncEnv, name: String) ) match module_path_owner_binding_decide(owners: scan.owners) { ModulePathBindingMiss => FuncSigUnresolved - ModulePathBindingHit { owner: _ } => + ModulePathBindingHit { owner: owner } => match scan.first_sig { - Present { value: sig } => FuncSigResolved { sig: sig } + Present { value: sig } => FuncSigResolved { sig: sig, owner_module_path: owner } Absent => FuncSigUnresolved } ModulePathBindingAmbiguous { owners: _ } => @@ -113,7 +113,12 @@ fn lookup_resolved_sig_unique_across_parents(env: ResolvedFuncEnv, name: String) } } -fn lookup_resolved_sig_with_telemetry(env: ResolvedFuncEnv, name: String) -> ResolvedFuncSig? { +type ResolvedSigWithOwner { + sig: ResolvedFuncSig + owner_module_path: String +} + +fn lookup_resolved_sig_with_telemetry(env: ResolvedFuncEnv, name: String) -> ResolvedSigWithOwner? { let scan = fold(env.parents, init: ParentSigScan { sig: none, match_count: 0, first_parent: none }, f: (acc, p) => match map_get(p.local, name) { Present { value: sig } => @@ -137,12 +142,19 @@ fn lookup_resolved_sig_with_telemetry(env: ResolvedFuncEnv, name: String) -> Res Absent => {} } } - scan.sig + match scan.sig { + Present { value: sig } => + match scan.first_parent { + Present { value: owner } => Present { value: ResolvedSigWithOwner { sig: sig, owner_module_path: owner } } + Absent => none + } + Absent => none + } } fn lookup_resolved_sig(env: ResolvedFuncEnv, name: String) -> FuncSigLookup { match map_get(env.local, name) { - Present { value: sig } => FuncSigResolved { sig: sig } + Present { value: sig } => FuncSigResolved { sig: sig, owner_module_path: env.name } Absent => if name_resolution_policy_is_namespace_only() { lookup_resolved_sig_unique_across_parents(env: env, name: name) @@ -150,22 +162,25 @@ fn lookup_resolved_sig(env: ResolvedFuncEnv, name: String) -> FuncSigLookup { let first_hit = if resolution_silent_pick_is_enabled() { lookup_resolved_sig_with_telemetry(env: env, name: name) } else { - fold(env.parents, init: none_resolved_sig(), f: (acc, p) => + fold(env.parents, init: none_resolved_sig_with_owner(), f: (acc, p) => match acc { - Present { value: sig } => Present { value: sig } - Absent => map_get(p.local, name) + Present { value: found } => Present { value: found } + Absent => match map_get(p.local, name) { + Present { value: sig } => Present { value: ResolvedSigWithOwner { sig: sig, owner_module_path: p.name } } + Absent => none + } } ) } match first_hit { - Present { value: sig } => FuncSigResolved { sig: sig } + Present { value: found } => FuncSigResolved { sig: found.sig, owner_module_path: found.owner_module_path } Absent => FuncSigUnresolved } } } } -fn none_resolved_sig() -> ResolvedFuncSig? { +fn none_resolved_sig_with_owner() -> ResolvedSigWithOwner? { Absent } diff --git a/src/v1/04_types.dag b/src/v1/04_types.dag index 7179eb5a0fe..9ffc78bdf8b 100644 --- a/src/v1/04_types.dag +++ b/src/v1/04_types.dag @@ -342,7 +342,9 @@ fn make_kernel_record_type(type_name: String, fields: List) -> Node { } fn make_container_type(kind_name: String, element: Node) -> KernelTypeBuild { - match container_param_name(kind_name: kind_name, index: 0) { + if !is_kernel_type(name: kind_name) { + KernelTypeBuild { ty: nominal_type_ref(name: kind_name), diagnostics: [] } + } else { match container_param_name(kind_name: kind_name, index: 0) { Present { value: param_name } => KernelTypeBuild { ty: Node { name: kind_name, span: kernel_span(name: kind_name), ident_span: Present { value: kernel_span(name: kind_name) }, children: [ @@ -355,7 +357,7 @@ fn make_container_type(kind_name: String, element: Node) -> KernelTypeBuild { ty: missing_kernel_container_profile_type(kind_name: kind_name), diagnostics: [kernel_container_profile_miss_diagnostic(kind_name: kind_name)] } - } + } } } fn make_map_type(key: Node, value: Node) -> KernelTypeBuild { @@ -607,14 +609,14 @@ fn apply_type_substitution(template: AlgebraTypeTemplate, subst: Map KernelTypeBuild { ty: elem, diagnostics: [] } Absent => let rname = container_kind_canonical(name: authored_name_at(source_indices: source_indices, node: receiver)) - match container_param_name(kind_name: rname, index: 0) { + if !is_kernel_type(name: rname) { KernelTypeBuild { ty: receiver, diagnostics: [] } } else { match container_param_name(kind_name: rname, index: 0) { Present { value: n } => KernelTypeBuild { ty: type_variable_node(id: n), diagnostics: [] } Absent => KernelTypeBuild { ty: missing_kernel_container_profile_type(kind_name: rname), diagnostics: [kernel_container_profile_miss_diagnostic(kind_name: rname)] } - } + } } } } ReceiverKey => @@ -625,14 +627,14 @@ fn apply_type_substitution(template: AlgebraTypeTemplate, subst: Map KernelTypeBuild { ty: key, diagnostics: [] } Absent => let rname = container_kind_canonical(name: authored_name_at(source_indices: source_indices, node: receiver)) - match container_param_name(kind_name: rname, index: 0) { + if !is_kernel_type(name: rname) { KernelTypeBuild { ty: receiver, diagnostics: [] } } else { match container_param_name(kind_name: rname, index: 0) { Present { value: n } => KernelTypeBuild { ty: type_variable_node(id: n), diagnostics: [] } Absent => KernelTypeBuild { ty: missing_kernel_container_profile_type(kind_name: rname), diagnostics: [kernel_container_profile_miss_diagnostic(kind_name: rname)] } - } + } } } } ReceiverValue => @@ -643,14 +645,14 @@ fn apply_type_substitution(template: AlgebraTypeTemplate, subst: Map KernelTypeBuild { ty: val, diagnostics: [] } Absent => let rname = container_kind_canonical(name: authored_name_at(source_indices: source_indices, node: receiver)) - match container_param_name(kind_name: rname, index: 1) { + if !is_kernel_type(name: rname) { KernelTypeBuild { ty: receiver, diagnostics: [] } } else { match container_param_name(kind_name: rname, index: 1) { Present { value: n } => KernelTypeBuild { ty: type_variable_node(id: n), diagnostics: [] } Absent => KernelTypeBuild { ty: missing_kernel_container_profile_type(kind_name: rname), diagnostics: [kernel_container_profile_miss_diagnostic(kind_name: rname)] } - } + } } } } NamedTemplate { name: n } => KernelTypeBuild { ty: nominal_type_ref(name: n), diagnostics: [] } diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index a23865b9b13..b0aef759fce 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -16,7 +16,8 @@ import v1.std.core { ExprCast, ExprForEach, ExprIndex, ExprSlice, ExprReturn, make_expr_node, FieldSummary, StoredField, EnumAccessor, OptionalUnwrap, TupleFirst, TupleSecond, OptionalValue, VarBindingKind, LocalValueBinding, FunctionValueBinding, VariantValueBinding, - MatchBoundBinding, CallSemantics, PlainCallSemantics, LookupCallSemantics, FunctionValueCallSemantics, MethodSemantics, + MatchBoundBinding, CallTargetIdentity, RuntimePrimitiveCall, SourceDeclarationCall, CallableTargetUndetermined, + CallSemantics, PlainCallSemantics, LookupCallSemantics, FunctionValueCallSemantics, MethodSemantics, PlainMethodSemantics, AlgebraMethodSemantics, ServiceMethodSemantics, MatchPattern, field_binding_pattern, TextFile, ErrorNode, make_error_node, InternalError, UnlistedImportUse, AmbiguousAnonymousRecordLiteral, SourceSpan, resource_use_resource, UnaryOpKind, StringPart, Text, @@ -8060,11 +8061,20 @@ fn call_semantics_is_function_value(cs: CallSemantics?) -> Bool { } } +fn call_semantics_target(cs: CallSemantics?) -> CallTargetIdentity { + match cs { + Present { value: PlainCallSemantics { target: target } } => target + Present { value: LookupCallSemantics { target: target } } => target + Present { value: FunctionValueCallSemantics } => CallableTargetUndetermined + Absent => CallableTargetUndetermined + } +} + fn emit_rust_expr_call(expr: Node, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { match expr.expr_data { ExprCall { call_semantics: cs, descent_evidence: _ } => let f = expr_call_func_at(texpr: expr, source_indices: scope.type_env.source_indices) - emit_typed_call_expr(func: f, args: expr.children, inferred: expr.inferred, callee_is_function_value: call_semantics_is_function_value(cs: cs), registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) + emit_typed_call_expr(func: f, args: expr.children, inferred: expr.inferred, callee_is_function_value: call_semantics_is_function_value(cs: cs), call_target: call_semantics_target(cs: cs), registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) _ => emit_error_expr(message: "emit_rust_expr_call expected ExprCall", target: Rust) } } @@ -8371,8 +8381,9 @@ fn emit_discriminant_call_scrutinee_lowering(arg: Node, registry: Map, inferred: InferredNode?, callee_is_function_value: Bool, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { - let call_str = if func == "empty_map" { +fn emit_typed_call_expr(func: String, args: List, inferred: InferredNode?, callee_is_function_value: Bool, call_target: CallTargetIdentity, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { + let target_is_runtime = match call_target { RuntimePrimitiveCall { primitive_name: _ } => true _ => false } + let call_str = if target_is_runtime && func == "empty_map" { match inferred { Present { value: Resolved { node: ret_type } } => let kv_type_str = rust_empty_map_kv_type_str(map_type: ret_type, shared_types: shared_types, source_indices: scope.type_env.source_indices) @@ -8383,17 +8394,17 @@ fn emit_typed_call_expr(func: String, args: List, inferred: InferredNode?, } _ => rust_shared_wrap_ctor(inner_expr: "HashMap::new() /* BRIDGE: empty_map return type unresolved */") } - } else if func == "empty_set" { + } else if target_is_runtime && func == "empty_set" { match inferred { Present { value: Resolved { node: ret_type } } => emit_rust_empty_set_expr(set_type: ret_type, shared_types: shared_types, source_indices: scope.type_env.source_indices, emit_info: emit_info) _ => "v1_rt::rc_empty_set::<_>()" } } else { - emit_typed_call(func: func, args: args, callee_is_function_value: callee_is_function_value, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) + emit_typed_call(func: func, args: args, callee_is_function_value: callee_is_function_value, call_target: call_target, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } - if callee_is_function_value == false && rust_runtime_bridge_wraps_collection_result_in_rc(function_name: func) { + if callee_is_function_value == false && match call_target { RuntimePrimitiveCall { primitive_name: primitive_name } => rust_runtime_bridge_wraps_collection_result_in_rc(function_name: primitive_name) _ => false } { rust_shared_wrap_ctor(inner_expr: call_str) } else { call_str } } @@ -8525,11 +8536,12 @@ fn lambda_argument_scope(arg: Node, scope: InferScope) -> InferScope { } } -fn emit_typed_call(func: String, args: List, callee_is_function_value: Bool, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { +fn emit_typed_call(func: String, args: List, callee_is_function_value: Bool, call_target: CallTargetIdentity, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { if callee_is_function_value { return emit_typed_function_value_call(func: func, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } - if func == "get" { + let target_is_runtime = match call_target { RuntimePrimitiveCall { primitive_name: _ } => true _ => false } + if target_is_runtime && func == "get" { let get_args = order_typed_call_args(args: args, func: func, scope: scope) let get_list = get_args |> first let get_idx = get_args |> skip(1) |> first @@ -8546,7 +8558,7 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo } return get_result } - if func == "with" { + if target_is_runtime && func == "with" { let with_args = order_typed_call_args(args: args, func: func, scope: scope) if with_args |> count == 0 { return "compile_error!(\"with call missing base record\")" } let base_arg = arg_value(n: (with_args |> first).value) @@ -8571,7 +8583,7 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo if needs_rc { return rust_shared_wrap_ctor(inner_expr: raw) } else { return raw } } - if func == "to_string" { + if target_is_runtime && func == "to_string" { let to_string_args = order_typed_call_args(args: args, func: func, scope: scope) let ts_result = match to_string_args |> first { Present { value: value_arg } => @@ -8581,7 +8593,7 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo return ts_result } - if func == "utf8_decode_bytes" { + if target_is_runtime && func == "utf8_decode_bytes" { let decode_args = order_typed_call_args(args: args, func: func, scope: scope) let decode_result = match decode_args |> first { Present { value: value_arg } => @@ -8594,7 +8606,7 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo } return decode_result } - if func == "discriminant" { + if target_is_runtime && func == "discriminant" { let disc_args = order_typed_call_args(args: args, func: func, scope: scope) let disc_result = match disc_args |> first { Present { value: value_arg } => @@ -8604,10 +8616,18 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo return disc_result } let ordered_args = order_typed_call_args(args: args, func: func, scope: scope) - let callee = lookup_item(registry: registry, name: qualified_last_segment(name: func)) + let callee = match call_target { + SourceDeclarationCall { owner_module_path: owner, decl_name: decl } => + lookup_item(registry: registry, name: concat(owner, ".", decl)) + _ => none + } let filled_args = fill_default_args(ordered: ordered_args, callee: callee, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) - let is_rt = callee_is_function_value == false && map_contains_key(rt_functions(), func) - let is_rt_ref_map = callee_is_function_value == false && map_contains_key(rt_ref_map_functions(), func) + let runtime_primitive_name = match call_target { + RuntimePrimitiveCall { primitive_name: primitive_name } => primitive_name + _ => "" + } + let is_rt = callee_is_function_value == false && runtime_primitive_name != "" + let is_rt_ref_map = is_rt && map_contains_key(rt_ref_map_functions(), runtime_primitive_name) let arg_strs = filled_args |> enumerate |> map(pair => let idx = pair.first let a = pair.second @@ -8633,14 +8653,20 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo } let all_args = concat(arg_strs, extra_args) let args_str = all_args |> join(separator: ", ") - let runtime_name = rust_runtime_bridge_name(function_name: func) + let runtime_name = rust_runtime_bridge_name(function_name: runtime_primitive_name) let si = scope.type_env.source_indices let callee_self_capture = if is_rt { false } else { filled_args |> any(a => expr_references_var(node: arg_value(n: a), var_name: func, source_indices: si)) } let func_ident = if is_rt { concat("v1_rt::", emit_ident(name: runtime_name, target: Rust)) } - else { emit_value_ref_ident(name: func, registry: registry, emit_info: emit_info) } + else { match call_target { + SourceDeclarationCall { owner_module_path: owner, decl_name: decl } => + if owner == scope.module_name { emit_ident(name: decl, target: Rust) } + else { concat("crate::", module_to_filename(name: owner), "::", emit_ident(name: decl, target: Rust)) } + CallableTargetUndetermined => emit_error_expr(message: "call target identity was not established before Rust emission", target: Rust) + RuntimePrimitiveCall { primitive_name: _ } => emit_error_expr(message: "runtime call target lost its bridge identity", target: Rust) + } } let func_name = if callee_self_capture { concat(func_ident, ".clone()") } else { func_ident } let call_str = if is_rt && func == "concat" && all_args |> count > 2 { emit_nested_rt_concat(remaining: all_args, acc: "", shared_types: shared_types) @@ -9267,13 +9293,13 @@ fn emit_rust_first_method_call(receiver: Node, registry: Map, } } -fn emit_rust_generic_method_call(method_name: String, receiver: Node, args: List, result_type: InferredNode?, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { +fn emit_rust_generic_method_call(method_name: String, receiver: Node, args: List, result_type: InferredNode?, runtime_bridge: Bool, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { let function_name = method_name - if rust_receiver_has_callable_method_field(receiver: receiver, method_name: function_name, scope: scope) { + if runtime_bridge == false && rust_receiver_has_callable_method_field(receiver: receiver, method_name: function_name, scope: scope) { let recv_str = emit_typed_expr_base(texpr: receiver, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) let arg_strs = args |> map(a => emit_cloned_arg(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info)) concat("(", recv_str, ".", emit_ident(name: function_name, target: Rust), ")(", arg_strs |> join(separator: ", "), ")") - } else if map_contains_key(rt_functions(), function_name) == false { + } else if runtime_bridge == false { let spec = language_spec(target: Rust) apply_type_template1(template: spec.error_type_template, arg0: concat("method ", function_name, " is neither a resolved callable receiver field nor a registered v1_rt bridge function")) } else { @@ -9346,7 +9372,7 @@ fn emit_typed_method_call(method_call_node: Node, receiver: Node, method: String } else if method_name == "with" { emit_rust_with_method_call(receiver: receiver, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } else if method_name == "string_contains" { - emit_rust_generic_method_call(method_name: "string_contains", receiver: receiver, args: args, result_type: result_type, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) + emit_rust_generic_method_call(method_name: "string_contains", receiver: receiver, args: args, result_type: result_type, runtime_bridge: true, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } else if method_name == "concat" { let recv_str = emit_typed_expr(texpr: receiver, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024) let arg_strs = args |> map(a => emit_typed_expr(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024)) @@ -9369,7 +9395,7 @@ fn emit_typed_method_call(method_call_node: Node, receiver: Node, method: String rust_shared_wrap_ctor(inner_expr: raw) } else { raw } Absent => - emit_rust_generic_method_call(method_name: method_name, receiver: receiver, args: args, result_type: result_type, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) + emit_rust_generic_method_call(method_name: method_name, receiver: receiver, args: args, result_type: result_type, runtime_bridge: true, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } } } @@ -9913,13 +9939,9 @@ fn rust_record_field_needs_fn_rc(scope: InferScope, struct_name: String, field_n } fn rust_receiver_has_callable_method_field(receiver: Node, method_name: String, scope: InferScope) -> Bool { - if map_contains_key(rt_functions(), method_name) { - false - } else { - let receiver_type = resolved_type(n: receiver) - let receiver_type_name = authored_name_at(source_indices: scope.type_env.source_indices, node: receiver_type) - rust_record_field_needs_fn_rc(scope: scope, struct_name: receiver_type_name, field_name: method_name) - } + let receiver_type = resolved_type(n: receiver) + let receiver_type_name = authored_name_at(source_indices: scope.type_env.source_indices, node: receiver_type) + rust_record_field_needs_fn_rc(scope: scope, struct_name: receiver_type_name, field_name: method_name) } fn rust_struct_field_type_node_variant_aware(scope: InferScope, emit_info: EmitGraphInfo, struct_name: String, field_name: String) -> Node? { @@ -10597,7 +10619,7 @@ fn emit_rust_tco_non_self_call(frame: TcoFrame, registry: Map, match frame.expr.expr_data { ExprCall { call_semantics: cs, descent_evidence: _ } => let f = expr_call_func_at(texpr: frame.expr, source_indices: frame.scope.type_env.source_indices) - let call_str = emit_typed_call(func: f, args: frame.expr.children, callee_is_function_value: call_semantics_is_function_value(cs: cs), registry: registry, scope: frame.scope, depth: frame.depth, shared_types: shared_types, emit_info: emit_info) + let call_str = emit_typed_call(func: f, args: frame.expr.children, callee_is_function_value: call_semantics_is_function_value(cs: cs), call_target: call_semantics_target(cs: cs), registry: registry, scope: frame.scope, depth: frame.depth, shared_types: shared_types, emit_info: emit_info) concat("break ", call_str, ";") _ => emit_error_expr(message: "emit_rust_tco_non_self_call expected ExprCall", target: Rust) } @@ -11908,6 +11930,7 @@ fn emit_capability_method(cap_node: Node, shared_types: Set, env: TypeEn fn data_value_has_cross_refs(value: Node) -> Bool { match value.expr_data { ExprVar { binding_kind: _ } => true + ExprCall { call_semantics: _, descent_evidence: _ } => true ExprListLit => value.children |> any(c => data_value_has_cross_refs(value: c)) ExprRecordLit { parent_enum: _ } => value.children |> any(f => data_value_has_cross_refs(value: field_init_node_value(n: f))) diff --git a/src/v1/compile.dag b/src/v1/compile.dag index c38dc83e3af..a928c443bbb 100644 --- a/src/v1/compile.dag +++ b/src/v1/compile.dag @@ -10,7 +10,9 @@ import v1.std.core { field_node_name_at, field_node_type_expr, field_node_cardinality, field_node_default_value, field_node_from_key, field_node_span, module_imports, module_items, import_is_all, import_specific_names_at, FieldAccessStyle, FieldValueShape, FieldSummary, InferredNode, - Resolved, CompilerError, TypeVariable, VarBindingKind, CallSemantics, MethodSemantics, + Resolved, CompilerError, TypeVariable, VarBindingKind, CallTargetIdentity, + RuntimePrimitiveCall, SourceDeclarationCall, CallableTargetUndetermined, + CallSemantics, PlainCallSemantics, LookupCallSemantics, FunctionValueCallSemantics, MethodSemantics, PlainMethodSemantics, AlgebraMethodSemantics, ServiceMethodSemantics, ExprErrorKind, OccurrenceTransportViolation, ExprData, MatchPattern, field_binding_name_at, field_binding_pattern, arg_name_at, arg_value, @@ -382,12 +384,22 @@ fn var_binding_kind_name(value: VarBindingKind) -> String { fn call_semantics_name(value: CallSemantics) -> String { match value { - PlainCallSemantics => "PlainCallSemantics" - LookupCallSemantics => "LookupCallSemantics" + PlainCallSemantics { target: _ } => "PlainCallSemantics" + LookupCallSemantics { target: _ } => "LookupCallSemantics" FunctionValueCallSemantics => "FunctionValueCallSemantics" } } +fn serialize_call_target_identity(value: CallTargetIdentity) -> String { + match value { + RuntimePrimitiveCall { primitive_name: primitive_name } => + concat("{\"kind\": \"RuntimePrimitiveCall\", \"primitive_name\": ", json_quote(s: primitive_name), "}") + SourceDeclarationCall { owner_module_path: owner, decl_name: decl } => + concat("{\"kind\": \"SourceDeclarationCall\", \"owner_module_path\": ", json_quote(s: owner), ", \"decl_name\": ", json_quote(s: decl), "}") + CallableTargetUndetermined => "{\"kind\": \"CallableTargetUndetermined\"}" + } +} + fn expr_error_kind_name(value: ExprErrorKind) -> String { match value { ParseRecoveryError => "ParseRecoveryError" @@ -522,8 +534,12 @@ fn serialize_string_part(part: StringPart, source_indices: Map String { match value { - Present { value: inner } => - concat("{\"kind\": ", json_quote(s: call_semantics_name(value: inner)), "}") + Present { value: PlainCallSemantics { target: target } } => + concat("{\"kind\": \"PlainCallSemantics\", \"target\": ", serialize_call_target_identity(value: target), "}") + Present { value: LookupCallSemantics { target: target } } => + concat("{\"kind\": \"LookupCallSemantics\", \"target\": ", serialize_call_target_identity(value: target), "}") + Present { value: FunctionValueCallSemantics } => + "{\"kind\": \"FunctionValueCallSemantics\"}" Absent => "null" } } diff --git a/src/v1/stage0/src/Cargo.toml b/src/v1/stage0/src/Cargo.toml new file mode 100644 index 00000000000..7997467206c --- /dev/null +++ b/src/v1/stage0/src/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "v1_compiler" +version = "0.1.0" +edition = "2021" + +[workspace] + +[dependencies] +im = { version = "15.1", features = ["serde"] } +unicode-ident = "1" +unicode-properties = { version = "0.1", features = ["emoji"] } +serde = { version = "1", features = ["derive", "rc"] } +serde_json = "1" +stacker = "0.1" +clap = { version = "4", features = ["derive"] } +lazy_static = "1" +ureq = { version = "2", features = ["json"] } diff --git a/src/v1/stage0/src/cli_run.rs b/src/v1/stage0/src/cli_run.rs index 356378435e8..64fb8e95f67 100644 --- a/src/v1/stage0/src/cli_run.rs +++ b/src/v1/stage0/src/cli_run.rs @@ -9091,115 +9091,6 @@ impl BudgetKind { } } -/// Mirror of `gunbc.observation_ci_render CiWitnessRuntimeCause`. One arm per -/// `v1_interpreter::InterpError` variant that can reach the witness boundary's untyped arm, and -/// no vocabulary of its own (DESIGN §3): the cause already exists upstream, this is it surviving -/// the seam. -/// -/// FIVE `InterpError` VARIANTS ARE DELIBERATELY ABSENT. `HostToolUnresolved`, -/// `HermeticHostEffectRefused`, `EvalBudgetExceeded`, `WitnessWallBudgetExceeded` and the -/// pre-mapped `EvaluationBudgetExceeded` each have their OWN `ClaimOutcome` arm and are consumed -/// by earlier arms of the match in `run_claim`, so they cannot reach this classifier. They are -/// not silently folded into a neighbour: all five map to `MappedOutcomeEscaped`, a typed, -/// countable diagnostic meaning the mapper let one through. One arm rather than five because all -/// five share ONE remedy — repair the mapper — and the descend-or-collapse rule turns on shared -/// remedy, not on arm count. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum WitnessRuntimeCause { - NoSuchFunction, - NoSuchVariable, - NoSuchField, - TypeError, - CrossRepresentationEquality, - StringRealizationStraddle, - PoolRootContributesNothing, - PatternMatchFailure, - DivisionByZero, - IntegerOverflow, - Unimplemented, - EarlyReturn, - AuthDeclaredButUnwired, - ServiceConfigUnresolved, - ServiceConfigMissing, - ArgvExceedsHostArgMax, - HostToolRelativePathAmbiguous, - ShellOutputLimitExceeded, - CallContractMismatch, - /// An `InterpError` with its own `ClaimOutcome` arm reached the untyped classifier anyway. - /// Loud rather than absorbed: this is a defect in the mapping above, and a run that produces - /// it should say so on the row rather than presenting the throw as an ordinary one. - MappedOutcomeEscaped, -} - -impl WitnessRuntimeCause { - /// Mirror of `ci_witness_runtime_cause_token`. Stable kebab tokens — the grep key a reader - /// uses to pair an identity with its cause. - pub fn token(self) -> &'static str { - match self { - WitnessRuntimeCause::NoSuchFunction => "no-such-function", - WitnessRuntimeCause::NoSuchVariable => "no-such-variable", - WitnessRuntimeCause::NoSuchField => "no-such-field", - WitnessRuntimeCause::TypeError => "type-error", - WitnessRuntimeCause::CrossRepresentationEquality => "cross-representation-equality", - WitnessRuntimeCause::StringRealizationStraddle => "string-realization-straddle", - WitnessRuntimeCause::PoolRootContributesNothing => "pool-root-contributes-nothing", - WitnessRuntimeCause::PatternMatchFailure => "pattern-match-failure", - WitnessRuntimeCause::DivisionByZero => "division-by-zero", - WitnessRuntimeCause::IntegerOverflow => "integer-overflow", - WitnessRuntimeCause::Unimplemented => "unimplemented", - WitnessRuntimeCause::EarlyReturn => "early-return", - WitnessRuntimeCause::AuthDeclaredButUnwired => "auth-declared-but-unwired", - WitnessRuntimeCause::ServiceConfigUnresolved => "service-config-unresolved", - WitnessRuntimeCause::ServiceConfigMissing => "service-config-missing", - WitnessRuntimeCause::ArgvExceedsHostArgMax => "argv-exceeds-host-arg-max", - WitnessRuntimeCause::HostToolRelativePathAmbiguous => { - "host-tool-relative-path-ambiguous" - } - WitnessRuntimeCause::ShellOutputLimitExceeded => "shell-output-limit-exceeded", - WitnessRuntimeCause::CallContractMismatch => "call-contract-mismatch", - WitnessRuntimeCause::MappedOutcomeEscaped => "mapped-outcome-escaped", - } - } - - /// TOTAL over `InterpError`. Totality is the point rather than a formality: a new interpreter - /// error variant must fail to compile HERE, where someone decides what its cause token is, - /// rather than inheriting a neighbour's or falling into a wildcard. - pub fn of_interp_error(err: &v1_interpreter::InterpError) -> Self { - use v1_interpreter::InterpError as E; - match err { - E::NoSuchFunction { .. } => WitnessRuntimeCause::NoSuchFunction, - E::NoSuchVariable { .. } => WitnessRuntimeCause::NoSuchVariable, - E::NoSuchField { .. } => WitnessRuntimeCause::NoSuchField, - E::TypeError { .. } => WitnessRuntimeCause::TypeError, - E::CrossRepresentationEquality { .. } => { - WitnessRuntimeCause::CrossRepresentationEquality - } - E::StringRealizationStraddle { .. } => WitnessRuntimeCause::StringRealizationStraddle, - E::PoolRootContributesNothing { .. } => WitnessRuntimeCause::PoolRootContributesNothing, - E::PatternMatchFailure { .. } => WitnessRuntimeCause::PatternMatchFailure, - E::DivisionByZero => WitnessRuntimeCause::DivisionByZero, - E::IntegerOverflow { .. } => WitnessRuntimeCause::IntegerOverflow, - E::Unimplemented { .. } => WitnessRuntimeCause::Unimplemented, - E::EarlyReturn { .. } => WitnessRuntimeCause::EarlyReturn, - E::AuthDeclaredButUnwired { .. } => WitnessRuntimeCause::AuthDeclaredButUnwired, - E::ServiceConfigUnresolved { .. } => WitnessRuntimeCause::ServiceConfigUnresolved, - E::ServiceConfigMissing { .. } => WitnessRuntimeCause::ServiceConfigMissing, - E::ArgvExceedsHostArgMax { .. } => WitnessRuntimeCause::ArgvExceedsHostArgMax, - E::HostToolRelativePathAmbiguous { .. } => { - WitnessRuntimeCause::HostToolRelativePathAmbiguous - } - E::ShellOutputLimitExceeded { .. } => WitnessRuntimeCause::ShellOutputLimitExceeded, - E::CallContractMismatch { .. } => WitnessRuntimeCause::CallContractMismatch, - // The five that should never arrive. See the type comment. - E::HostToolUnresolved { .. } - | E::HermeticHostEffectRefused { .. } - | E::EvalBudgetExceeded { .. } - | E::WitnessWallBudgetExceeded { .. } - | E::EvaluationBudgetExceeded { .. } => WitnessRuntimeCause::MappedOutcomeEscaped, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq)] pub enum ClaimOutcome { Pass, @@ -9207,26 +9098,7 @@ pub enum ClaimOutcome { NotBool { got: String, }, - /// A THROW, WITH THE REASON IT THREW KEPT AS A TYPE. - /// - /// `message` used to be the whole content of this arm, built by `format!("{other}")` over - /// `v1_interpreter::InterpError` — which is ALREADY a closed 24-arm coproduct. So the cause - /// was known at this seam, destroyed here, and then guessed back downstream by slicing the - /// first twelve whitespace-separated words off the prose (`known_red_runtime_error_causes`). - /// That key embeds the missing NAME, so `no declaration named X` and `no declaration named Y` - /// counted as two causes: on main `f9963a762` the floor reported **65 distinct signatures** - /// across 142 identities for a population with about four actual causes. The number was an - /// artifact of the key, and it said "many roots" where the truth is "one root, many names". - /// - /// This is the same repair `TimedOut` and `HostToolUnresolved` above already received, for - /// the same stated reason, and the third instance is the argument for doing it by type - /// rather than case by case. - /// - /// `message` SURVIVES beside the cause and is not redundant with it: the cause says WHICH - /// class, the message says which name, which type, which arity. Two facts, two fields — the - /// defect was never that prose existed, it was that prose was the only representation. RuntimeError { - cause: WitnessRuntimeCause, message: String, }, /// A budget refusal, with the pair that explains it kept as data. @@ -16705,10 +16577,7 @@ pub enum CiWitnessVerdict { Passed, Failed, NotBool, - /// Carries the cause as a PAYLOAD rather than beside the verdict, so "a PASSED row with a - /// cause" and "an ERROR row without one" have no spelling (DESIGN §4b: structurally - /// impossible, not merely checked). - RuntimeError(WitnessRuntimeCause), + RuntimeError, BudgetRefused, /// THE CLAIM PASSED AND WAS THEN RECLASSIFIED ON COST. Distinct from `BudgetRefused` /// because it reached a verdict: the remedy is to pay the cost down, not to find out what @@ -16731,7 +16600,7 @@ impl CiWitnessVerdict { CiWitnessVerdict::Passed => "PASSED", CiWitnessVerdict::Failed => "FAILED", CiWitnessVerdict::NotBool => "NOT-BOOL", - CiWitnessVerdict::RuntimeError(_) => "ERROR", + CiWitnessVerdict::RuntimeError => "ERROR", CiWitnessVerdict::BudgetRefused => "BUDGET-REFUSED", CiWitnessVerdict::PassedOverBudget => "PASSED-OVER-BUDGET", CiWitnessVerdict::HostToolUnresolved => "TOOL-UNRESOLVED", @@ -16780,7 +16649,7 @@ impl CiWitnessVerdict { ClaimOutcome::Pass => CiWitnessVerdict::Passed, ClaimOutcome::Fail => CiWitnessVerdict::Failed, ClaimOutcome::NotBool { .. } => CiWitnessVerdict::NotBool, - ClaimOutcome::RuntimeError { cause, .. } => CiWitnessVerdict::RuntimeError(*cause), + ClaimOutcome::RuntimeError { .. } => CiWitnessVerdict::RuntimeError, // SITE 1 OF THE FIVE THAT DROPPED THE AXIS. `BudgetRefused` is true only of the // interrupted arm; a completed-over-budget row REACHED ITS VERDICT and was refused // nothing, so reporting it as a refusal erased the verdict it had already produced. @@ -16812,22 +16681,8 @@ pub fn render_witness_claim_result_text_mirror( ) }; let token = verdict.token(); - // Mirror of `ci_witness_cause_field`: trailing and key-tagged, so a reader pairs identity - // with cause by KEY and never by column offset. Empty for every arm that has no cause, - // which keeps every existing line byte-identical. - let cause = match verdict { - CiWitnessVerdict::RuntimeError(cause) => format!(" cause={}", cause.token()), - CiWitnessVerdict::Passed - | CiWitnessVerdict::Failed - | CiWitnessVerdict::NotBool - | CiWitnessVerdict::BudgetRefused - | CiWitnessVerdict::HostToolUnresolved - | CiWitnessVerdict::KnownRed - | CiWitnessVerdict::PassedOverBudget - | CiWitnessVerdict::RouteGap => String::new(), - }; format!( - "{padded}{token} in {}{cause}", + "{padded}{token} in {}", crate::v1_rt::obs_human_elapsed(wall_nanos) ) } @@ -18372,12 +18227,7 @@ pub fn run_claim(ctx: &v1_interpreter::InterpContext, function: &str) -> ClaimOu kind: BudgetKind::Wall, } } - // THE CLASSIFICATION HAPPENS HERE, where `other` is still a typed `InterpError`. - // It is a projection of a value in hand, not a derivation: nothing is parsed, - // matched or guessed, and there is no site downstream that could do this at all - // once the `format!` has run. other => ClaimOutcome::RuntimeError { - cause: WitnessRuntimeCause::of_interp_error(&other), message: format!("{other}"), }, }, @@ -18774,7 +18624,7 @@ pub fn claim_terminal_detail(outcome: &ClaimOutcome) -> String { match outcome { ClaimOutcome::Pass | ClaimOutcome::Fail => String::new(), ClaimOutcome::NotBool { got } => got.clone(), - ClaimOutcome::RuntimeError { message, .. } => message.clone(), + ClaimOutcome::RuntimeError { message } => message.clone(), ClaimOutcome::BudgetInterrupted { kind, .. } | ClaimOutcome::CompletedOverBudget { kind, .. } => kind.label().to_string(), ClaimOutcome::HostToolUnresolved { name, .. } => name.clone(), @@ -21227,7 +21077,7 @@ pub fn project_witness_cost_receipt( )); "witness_cost_seed_refused_event" } - ClaimOutcome::RuntimeError { message, .. } => { + ClaimOutcome::RuntimeError { message } => { args.push(( Some("error".to_string()), str_value(format!("runtime error: {message}")), @@ -27083,7 +26933,7 @@ fn run_discovery_rows( "{} ({}) returned `{}`, not Bool", row.function, row.entry, got )), - ClaimOutcome::RuntimeError { message, .. } => summary.failures.push(format!( + ClaimOutcome::RuntimeError { message } => summary.failures.push(format!( "{} ({}) runtime error: {}", row.function, row.entry, message )), @@ -35286,25 +35136,6 @@ fn compute_inert_carrier_data(files: &[(String, String)]) -> InertCarrierData { if decl_count.get(name).copied().unwrap_or(0) != 1 { continue; } - // INTENDED SCOPE GATE, not an oversight. This lens answers ONE question -- - // DESIGN §5 coverage-by-illusion: a carrier that a test makes look exercised - // while no production code reads it. A carrier that is referenced by NOTHING, - // test included, is a different class with a different remedy (delete it, or - // write the missing test and let it land here), so it cannot share this - // roster: a roster row means "modeled ahead of its consumer, tested, awaiting - // one", and every one of these would be a row asserting a test that does not - // exist. That class is owned by the still-unbuilt run-root reachability cut - // (gunbc.plans.inert_layer_lens, `v2.lens.inert_layer`), whose retirement - // condition names it. Measured over `dag` + `src/v2` at 32597358f16 on - // 2026-08-24: 8821 declared carriers, 14 flagged here, 270 skipped by this - // line -- the same order the plan predicted for a raw sweep ("hundreds"), - // which is why the two are separate cuts and not one roster. A dated - // observation, not a bound: nothing gates on either number. - // `green_control_untested_unused_carrier_is_not_flagged` below is the - // executing control that keeps this exclusion deliberate rather than latent: - // it plants exactly this carrier and asserts it stays off the roster, so - // deleting this line goes red -- executed both ways 2026-08-24: gate present, - // 12 passed; gate deleted, that one control fails with got ["Staged"]. if !self_tested.contains(name) { continue; } @@ -44743,7 +44574,7 @@ pub fn run_required_floor( // accounting while being wrong about the SHAPE of the problem, and a later reader prices // N repairs against what may be one fix. Grouping here costs a HashMap and answers it on // the same run that produces the count. - let mut known_red_runtime_error_causes: HashMap<&'static str, usize> = HashMap::new(); + let mut known_red_runtime_error_causes: HashMap = HashMap::new(); let mut known_red_observation_unreadable_count: usize = 0; // WHICH ENROLLED ROUTE-GAP IDENTITIES ACTUALLY GAPPED, for the reverse join below. Without // it the roster is a one-way lookup that only ever asks "is this gap enrolled" and never @@ -45109,32 +44940,27 @@ pub fn run_required_floor( // strength of an error, which is the exact rot this lane exists to surface. ExpectedRedArm::RuntimeErrored => { known_red_runtime_errored_count += 1; - // KEYED ON THE TYPED CAUSE, NOT ON THE PROSE. The previous key was the - // first twelve whitespace-separated words of the message — which EMBEDS THE - // MISSING NAME, so `no declaration named X` and `no declaration named Y` - // counted as two distinct causes. Measured on main `f9963a762`: 65 distinct - // "signatures" across 142 identities, for a population with four actual - // causes. That is not an imprecise number, it is an inverted one — it told - // every reader "many roots" where the truth is "one root, many names", and - // pointed them away from the single repair that closes most of the - // population. The comment it replaced described the key as normalizing away - // per-row identities; it did the opposite. let detail = match &result { - ClaimOutcome::RuntimeError { cause, message } => { + ClaimOutcome::RuntimeError { message } => { + // NORMALIZED TO A SIGNATURE, not kept verbatim: identities, paths and + // offsets differ per row and would make every throw its own "cause", + // which is the answer the census exists to avoid assuming. + let signature: String = message + .split_whitespace() + .take(12) + .collect::>() + .join(" "); *known_red_runtime_error_causes - .entry(cause.token()) + .entry(signature.chars().take(140).collect()) .or_insert(0) += 1; - format!("runtime error [{}]: {message}", cause.token()) + format!("runtime error: {message}") } - // NOT a fallback that guesses. Only `RuntimeErrored` reaches this arm and - // only `RuntimeError` produces it, so this is unreachable in fact; it is - // kept, and kept LOUD, because unreachable is not the same as absent and - // a silent `_ => ()` here would hide a real routing defect. other => { + let rendered = format!("{other:?}"); *known_red_runtime_error_causes - .entry("routing-defect-non-runtime-error-in-runtime-errored-arm") + .entry(rendered.chars().take(140).collect()) .or_insert(0) += 1; - format!("{other:?}") + rendered } }; outcome.known_red_runtime_errored.push(format!( @@ -45182,7 +45008,7 @@ pub fn run_required_floor( ClaimOutcome::NotBool { got } => outcome .failures .push(format!("{} answered {got}, not a Bool", claim.qualified)), - ClaimOutcome::RuntimeError { message, .. } => outcome + ClaimOutcome::RuntimeError { message } => outcome .failures .push(format!("{} errored: {message}", claim.qualified)), ClaimOutcome::HostToolUnresolved { name, probed } => outcome.failures.push(format!( @@ -45348,39 +45174,17 @@ pub fn run_required_floor( // per-identity report runs — on precisely the run where the evidence matters, it would be // computed and dropped. if !known_red_runtime_error_causes.is_empty() { - let mut causes: Vec<(&&'static str, &usize)> = - known_red_runtime_error_causes.iter().collect(); + let mut causes: Vec<(&String, &usize)> = known_red_runtime_error_causes.iter().collect(); causes.sort_by(|a, b| b.1.cmp(a.1).then(a.0.cmp(b.0))); eprintln!( - "[floor-known-red-causes] {} distinct cause(s) across {} non-verdict enrolled \ + "[floor-known-red-causes] {} distinct signature(s) across {} non-verdict enrolled \ identity(ies)", causes.len(), known_red_runtime_errored_count + known_red_observation_unreadable_count ); - // THE CAP IS PRINTED, NOT RAISED, AND IT IS PRINTED WHETHER OR NOT IT BIT. Truncating at - // 20 was not wrong because 20 is small; it was wrong because nothing said anything had - // been dropped, so a reader tallying the printed rows got a short total with no way to - // know it — 93 of 142 on main `f9963a762`, and an experienced reader looked straight at - // that line without noticing the rows did not sum. Raising the cap would fix one run and - // leave the same silence for the next. - // - // `not_listed=0` IS THE LOAD-BEARING CASE. A drop notice that appears only when - // something drops requires the reader to know the field exists in order to miss it, - // which is the same silence one step quieter. Printing it always makes a complete - // listing say so, in the same place and the same shape as a truncated one. - const CAUSE_ROWS: usize = 20; - let dropped_rows = causes.len().saturating_sub(CAUSE_ROWS); - let dropped_identities: usize = causes.iter().skip(CAUSE_ROWS).map(|(_, c)| **c).sum(); - let listed_identities: usize = causes.iter().take(CAUSE_ROWS).map(|(_, c)| **c).sum(); - for (cause, count) in causes.iter().take(CAUSE_ROWS) { - eprintln!("[floor-known-red-causes] {count} × {cause}"); + for (signature, count) in causes.iter().take(20) { + eprintln!("[floor-known-red-causes] {count} × {signature}"); } - eprintln!( - "[floor-known-red-causes] listed={} listing_cap={CAUSE_ROWS} \ - not_listed={dropped_rows} not_listed_identities={dropped_identities} \ - listed_identities={listed_identities}", - causes.len().min(CAUSE_ROWS) - ); } eprintln!( "[floor-claim-memory] worst single claim grew rss by {:.2}GB at={}", @@ -46150,7 +45954,7 @@ fn witness_eval_verdict_from_claim_outcome( got: got.clone(), } } - ClaimOutcome::RuntimeError { message, .. } => { + ClaimOutcome::RuntimeError { message } => { crate::v1_compiler_expected_red_roster_join::WitnessEvalVerdict::RuntimeError { message: message.clone(), } @@ -46329,7 +46133,6 @@ mod terminal_ledger_completeness_law { (ClaimOutcome::Fail, true, KnownRedHeld), ( ClaimOutcome::RuntimeError { - cause: WitnessRuntimeCause::TypeError, message: "boom".into(), }, false, diff --git a/src/v1/stage0/src/emitted_population.rs b/src/v1/stage0/src/emitted_population.rs index bcc8411a7b3..dd27630a501 100644 --- a/src/v1/stage0/src/emitted_population.rs +++ b/src/v1/stage0/src/emitted_population.rs @@ -65,6 +65,7 @@ // src/std_occurrence_binding_resolve.rs // src/std_occurrence_identity.rs // src/std_pareto.rs +// src/std_primitive_projection.rs // src/std_process_termination.rs // src/std_realization_schedule.rs // src/std_reference_binding_observation.rs @@ -130,6 +131,7 @@ // src/v1_std_core.rs // src/v1_test_non_ascii_perf_fixture.rs // src/v1_tests_claim_checkpoint_identity_keying_witness_test.rs +// src/v1_tests_claim_resolved_call_emission_identity_internal_witness_test.rs // src/v1_tests_claim_transport_roster_closure_witness_test.rs // src/wt_a.rs // src/wt_b.rs diff --git a/src/v1/stage0/src/lib.rs b/src/v1/stage0/src/lib.rs index 4eec3ac34d3..2f173035cec 100644 --- a/src/v1/stage0/src/lib.rs +++ b/src/v1/stage0/src/lib.rs @@ -77,6 +77,7 @@ pub mod std_occurrence_binding_candidates; pub mod std_occurrence_binding_resolve; pub mod std_occurrence_identity; pub mod std_pareto; +pub mod std_primitive_projection; pub mod std_process_termination; pub mod std_realization_schedule; pub mod std_reference_binding_observation; @@ -142,6 +143,7 @@ pub mod v1_rt; pub mod v1_std_core; pub mod v1_test_non_ascii_perf_fixture; pub mod v1_tests_claim_checkpoint_identity_keying_witness_test; +pub mod v1_tests_claim_resolved_call_emission_identity_internal_witness_test; pub mod v1_tests_claim_transport_roster_closure_witness_test; pub mod wt_a; pub mod wt_b; diff --git a/src/v1/stage0/src/std_primitive_projection.rs b/src/v1/stage0/src/std_primitive_projection.rs new file mode 100644 index 00000000000..fc0208fdc08 --- /dev/null +++ b/src/v1/stage0/src/std_primitive_projection.rs @@ -0,0 +1,301 @@ +// Generated by v1 compiler -- do not edit. +// Source module: std.primitive_projection + +use self::PrimitiveProjectionAnswer::*; +use self::ProjectionFidelity::*; +pub use crate::std_decl_ref::DeclarationRef; +pub use crate::std_decl_ref::{decl_ref, declaration_ref_eq}; +pub use crate::std_types::{List, NonEmptyStr}; +use crate::v1_rt; +use crate::v1_rt::{VecCompat, VecJoin}; +use crate::NonEmptyBTreeSet; +use crate::NonEmptyVec; +use im::{vector as vec, HashMap, OrdSet as BTreeSet, Vector as Vec}; +use std::rc::Rc; + +pub fn primitive_projection_seed_boundary_note() -> String { + thread_local! { + static CACHED: String = { + "The declaration-to-primitive projection is a seed-consumed substrate authority, so its import closure stops at std.decl_ref/std.types and never reaches a target roster or v2 module. This module is a strict relocation of the projection identity, fidelity, roster, and exact-declaration query formerly declared inside std.primitive_identity. std.primitive_identity consumes this authority for its census and total disposed/undisposed answer; the stage0 resolver consumes the same exact-declaration query. Required regen is the mechanical wall: src/v1 importing the former home reached gunbc.v1_interpreter_primitive_surface and then v2.std.qualified_name, which the src/v1 + dag bootstrap closure correctly refuses. The refusal is the seed-safety boundary working, not build friction.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +pub fn primitive_identity_slug_prefix() -> String { + thread_local! { + static CACHED: String = { + "primitive.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PrimitiveIdentity { + pub slug: NonEmptyStr, +} + +pub fn primitive_identity_slug(name: String) -> Rc { + Rc::new(PrimitiveIdentity { + slug: v1_rt::concat(primitive_identity_slug_prefix(), name.clone()), + }) +} + +pub fn primitive_identity_runtime_name(identity: Rc) -> String { + { + let slug = identity.slug.clone(); + v1_rt::substring( + &slug, + v1_rt::string_length(&primitive_identity_slug_prefix()), + v1_rt::string_length(&slug), + ) + } +} + +pub fn primitive_projection_identity_key_note() -> String { + thread_local! { + static CACHED: String = { + "The projection is keyed on std.decl_ref DeclarationRef, which is the namespace layer's own identity for a declaration (DESIGN section 3: namespace supplies declaration identity, this carrier supplies semantic primitive identity). No new identity type is minted here. The alternative shape considered and refused was a per-declaration marker row beside each fn: it is a second representation scattered across modules rather than one authority, it keys on a bare name inside a module scope so two same-named declarations collapse into one, and it has no room for a fidelity distinction. Module qualification answers the second; this single carrier answers the first; ProjectionFidelity answers the third.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +pub fn primitive_projection_fidelity_note() -> String { + thread_local! { + static CACHED: String = { + "HostRealizedSeam and ModeledProjection agree at the resolver -- both mean the declaration and the primitive are ONE authority, so a candidate collector must not report them as two. They are kept apart because they are different facts with different futures, and averaging them into one flag would erase the difference. A HostRealizedSeam body is a SELF-CALL (v2.std.decl_index decl_facts is decl_facts(pool_roots: pool_roots)): it is correct by construction, because a body that could never survive being reached is exactly what a declared host seam should look like -- reaching it recurses to the evaluation-budget refusal. A ModeledProjection body is REAL CODE that the builtin arm intercepts ahead of user-fn dispatch (v2.std.algebra length has a genuine fold_list body no bare call reaches): it is dead code that looks live, and someone will eventually edit it believing it runs. This carrier makes that observable rather than folklore. Repairing the dead-code half is NOT this carrier's job and is not claimed here.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum ProjectionFidelity { + HostRealizedSeam, + ModeledProjection, + DivergentProjection { divergence: NonEmptyStr }, +} +impl ProjectionFidelity { + pub fn divergence(&self) -> NonEmptyStr { + match self { + ProjectionFidelity::HostRealizedSeam => panic!("no divergence on unit variant"), + ProjectionFidelity::ModeledProjection => panic!("no divergence on unit variant"), + ProjectionFidelity::DivergentProjection { + divergence: __val, .. + } => __val.clone(), + } + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PrimitiveProjection { + pub primitive: Rc, + pub declaration: Rc, + pub fidelity: Rc, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum PrimitiveProjectionAnswer { + DeclarationProjectsPrimitive { + identity: Rc, + fidelity: Rc, + }, + DeclarationProjectsNoPrimitive, + DeclarationPrimitiveUndisposed { + authored_symbol: NonEmptyStr, + }, +} + +pub fn primitive_length() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_map_insert() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_map_get() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_empty_map() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_decl_facts() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_export_signature_facts() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_data_decl_type_facts() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_concept_decl_facts() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_concept_decl_facts_live() -> Rc { + thread_local! { + static CACHED: Rc = { + compile_error!("unsupported mock expression") + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_projection_roster_note() -> String { + thread_local! { + static CACHED: String = { + "One row per declaration that is the modeled surface of a declared primitive. Every row was established by READING THE DECLARATION, not by matching its name: the HostRealizedSeam rows are declarations whose whole body is a self-call, and the ModeledProjection rows are declarations with a real body that the builtin arm intercepts ahead of. The single DivergentProjection row is v2.std.collection map_get, whose declared return type is Outcome> against the primitive's Optional; it is carried rather than omitted because omission and divergence are different answers -- omission means nobody has looked, divergence means someone looked and found two authorities. A consumer collecting call candidates must suppress the builtin co-candidate for the first two fidelities and must keep refusing on the third.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +pub fn primitive_projection_row( + primitive: Rc, + module_path: String, + decl_name: String, + fidelity: Rc, +) -> Rc { + Rc::new(PrimitiveProjection { + primitive: primitive.clone(), + declaration: decl_ref(module_path.clone(), decl_name.clone()), + fidelity: fidelity.clone(), + }) +} + +pub fn primitive_projection_roster() -> Rc>> { + Rc::new(vec![ + primitive_projection_row( + primitive_decl_facts(), + "v2.std.decl_index".to_string(), + "decl_facts".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), + primitive_projection_row( + primitive_export_signature_facts(), + "v2.std.decl_index".to_string(), + "export_signature_facts".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), + primitive_projection_row( + primitive_data_decl_type_facts(), + "v2.std.decl_index".to_string(), + "data_decl_type_facts".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), + primitive_projection_row( + primitive_concept_decl_facts(), + "v2.std.concept_index".to_string(), + "concept_decl_facts".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), + primitive_projection_row( + primitive_concept_decl_facts_live(), + "v2.std.concept_index".to_string(), + "concept_decl_facts_live".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), + primitive_projection_row( + primitive_empty_map(), + "v2.std.collection".to_string(), + "empty_map_primitive_delegate".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), + primitive_projection_row( + primitive_length(), + "v2.std.algebra".to_string(), + "length".to_string(), + Rc::new(ProjectionFidelity::ModeledProjection), + ), + primitive_projection_row( + primitive_map_insert(), + "v2.std.collection".to_string(), + "map_insert".to_string(), + Rc::new(ProjectionFidelity::ModeledProjection), + ), + primitive_projection_row( + primitive_empty_map(), + "v2.std.collection".to_string(), + "empty_map".to_string(), + Rc::new(ProjectionFidelity::ModeledProjection), + ), + primitive_projection_row( + primitive_map_get(), + "v2.std.collection".to_string(), + "map_get".to_string(), + Rc::new(ProjectionFidelity::DivergentProjection { + divergence: + "declared return Outcome> against the primitive's Optional" + .to_string(), + }), + ), + ]) +} + +pub fn primitive_projection_row_for_declaration( + declaration: Rc, +) -> Option> { + primitive_projection_roster().iter().cloned().fold( + None, + |acc: _, row: Rc| match acc.clone() { + Some(_) => acc.clone(), + None => { + if declaration_ref_eq(row.declaration.clone(), declaration.clone()) { + Some(row.clone()) + } else { + acc.clone() + } + } + }, + ) +} diff --git a/src/v1/stage0/src/v1_compiler_compile.rs b/src/v1/stage0/src/v1_compiler_compile.rs index 745da0a3b89..af188f863c5 100644 --- a/src/v1/stage0/src/v1_compiler_compile.rs +++ b/src/v1/stage0/src/v1_compiler_compile.rs @@ -67,7 +67,12 @@ pub use crate::v1_compiler_resolve::{ModuleGraph, ModuleOccurrenceInput}; pub use crate::v1_compiler_tokenize::tokenize_artifact; use crate::v1_rt; use crate::v1_rt::{VecCompat, VecJoin}; -use crate::v1_std_core::CallSemantics::*; +use crate::v1_std_core::CallSemantics::{ + FunctionValueCallSemantics, LookupCallSemantics, PlainCallSemantics, +}; +use crate::v1_std_core::CallTargetIdentity::{ + CallableTargetUndetermined, RuntimePrimitiveCall, SourceDeclarationCall, +}; use crate::v1_std_core::Cardinality::*; use crate::v1_std_core::CompilerDiagnostic::{ InternalError, OccurrenceTransportViolation, OwnershipViolation, @@ -98,10 +103,10 @@ pub use crate::v1_std_core::{ record_lit_type_name_at, resource_use_name_at, resource_use_resource, }; pub use crate::v1_std_core::{ - CallSemantics, Cardinality, CompileResult, CompilerDiagnostic, Connective, ErrorNode, ExprData, - ExprErrorKind, FieldAccessStyle, FieldSummary, FieldValueShape, InferredNode, InternTable, - MatchPattern, MethodSemantics, NewlineIndex, Node, StringPart, TextFile, Token, UnaryOpKind, - VarBindingKind, + CallSemantics, CallTargetIdentity, Cardinality, CompileResult, CompilerDiagnostic, Connective, + ErrorNode, ExprData, ExprErrorKind, FieldAccessStyle, FieldSummary, FieldValueShape, + InferredNode, InternTable, MatchPattern, MethodSemantics, NewlineIndex, Node, StringPart, + TextFile, Token, UnaryOpKind, VarBindingKind, }; use crate::NonEmptyBTreeSet; use crate::NonEmptyVec; @@ -732,14 +737,49 @@ pub fn var_binding_kind_name(value: Rc) -> String { } } -pub fn call_semantics_name(value: CallSemantics) -> String { - match value.clone() { - CallSemantics::PlainCallSemantics => "PlainCallSemantics".to_string(), - CallSemantics::LookupCallSemantics => "LookupCallSemantics".to_string(), +pub fn call_semantics_name(value: Rc) -> String { + match (*value.clone()).clone() { + CallSemantics::PlainCallSemantics { target: _, .. } => "PlainCallSemantics".to_string(), + CallSemantics::LookupCallSemantics { target: _, .. } => "LookupCallSemantics".to_string(), CallSemantics::FunctionValueCallSemantics => "FunctionValueCallSemantics".to_string(), } } +pub fn serialize_call_target_identity(value: Rc) -> String { + match (*value.clone()).clone() { + CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: primitive_name, + .. + } => v1_rt::concat( + v1_rt::concat( + "{\"kind\": \"RuntimePrimitiveCall\", \"primitive_name\": ".to_string(), + json_quote(primitive_name.clone()), + ), + "}".to_string(), + ), + CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner, + decl_name: decl, + .. + } => v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + "{\"kind\": \"SourceDeclarationCall\", \"owner_module_path\": ".to_string(), + json_quote(owner.clone()), + ), + ", \"decl_name\": ".to_string(), + ), + json_quote(decl.clone()), + ), + "}".to_string(), + ), + CallTargetIdentity::CallableTargetUndetermined => { + "{\"kind\": \"CallableTargetUndetermined\"}".to_string() + } + } +} + pub fn expr_error_kind_name(value: ExprErrorKind) -> String { match value.clone() { ExprErrorKind::ParseRecoveryError => "ParseRecoveryError".to_string(), @@ -1068,15 +1108,25 @@ pub fn serialize_string_part( } } -pub fn serialize_call_semantics(value: Option) -> String { - match value.clone() { - Some(inner) => v1_rt::concat( +pub fn serialize_call_semantics(value: Option>) -> String { + match value.clone().as_deref().cloned() { + Some(CallSemantics::PlainCallSemantics { target: target, .. }) => v1_rt::concat( + v1_rt::concat( + "{\"kind\": \"PlainCallSemantics\", \"target\": ".to_string(), + serialize_call_target_identity(target.clone()), + ), + "}".to_string(), + ), + Some(CallSemantics::LookupCallSemantics { target: target, .. }) => v1_rt::concat( v1_rt::concat( - "{\"kind\": ".to_string(), - json_quote(call_semantics_name(inner.clone())), + "{\"kind\": \"LookupCallSemantics\", \"target\": ".to_string(), + serialize_call_target_identity(target.clone()), ), "}".to_string(), ), + Some(CallSemantics::FunctionValueCallSemantics) => { + "{\"kind\": \"FunctionValueCallSemantics\"}".to_string() + } None => "null".to_string(), } } diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 29e29ba7b16..6f4d1fa45f2 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -152,6 +152,9 @@ use crate::v1_rt::{VecCompat, VecJoin}; use crate::v1_std_core::CallSemantics::{ FunctionValueCallSemantics, LookupCallSemantics, PlainCallSemantics, }; +use crate::v1_std_core::CallTargetIdentity::{ + CallableTargetUndetermined, RuntimePrimitiveCall, SourceDeclarationCall, +}; use crate::v1_std_core::Cardinality::{CardOptional, Required}; use crate::v1_std_core::CompilerDiagnostic::{ AmbiguousAnonymousRecordLiteral, InternalError, UnlistedImportUse, @@ -198,9 +201,9 @@ pub use crate::v1_std_core::{ transport_stdin, transport_tls_posture, tuple_type_name, with_required_cardinality, }; pub use crate::v1_std_core::{ - CallSemantics, Cardinality, CompilerDiagnostic, Connective, ErrorNode, ExprData, - FieldAccessStyle, FieldSummary, FieldValueShape, InferredNode, MatchPattern, MethodSemantics, - NewlineIndex, Node, StringPart, TextFile, UnaryOpKind, VarBindingKind, + CallSemantics, CallTargetIdentity, Cardinality, CompilerDiagnostic, Connective, ErrorNode, + ExprData, FieldAccessStyle, FieldSummary, FieldValueShape, InferredNode, MatchPattern, + MethodSemantics, NewlineIndex, Node, StringPart, TextFile, UnaryOpKind, VarBindingKind, }; use crate::NonEmptyBTreeSet; use crate::NonEmptyVec; @@ -20001,13 +20004,24 @@ pub fn emit_rust_expr_field_access( } } -pub fn call_semantics_is_function_value(cs: Option) -> bool { - match cs.clone() { +pub fn call_semantics_is_function_value(cs: Option>) -> bool { + match cs.clone().as_deref().cloned() { Some(CallSemantics::FunctionValueCallSemantics) => true, _ => false, } } +pub fn call_semantics_target(cs: Option>) -> Rc { + match cs.clone().as_deref().cloned() { + Some(CallSemantics::PlainCallSemantics { target: target, .. }) => target.clone(), + Some(CallSemantics::LookupCallSemantics { target: target, .. }) => target.clone(), + Some(CallSemantics::FunctionValueCallSemantics) => { + Rc::new(CallTargetIdentity::CallableTargetUndetermined) + } + None => Rc::new(CallTargetIdentity::CallableTargetUndetermined), + } +} + pub fn emit_rust_expr_call( expr: Rc, registry: Rc>>, @@ -20026,6 +20040,7 @@ pub fn emit_rust_expr_call( expr.children.clone(), expr.inferred.clone(), call_semantics_is_function_value(cs.clone()), + call_semantics_target(cs.clone()), registry.clone(), scope.clone(), depth.clone(), @@ -20986,6 +21001,7 @@ pub fn emit_typed_call_expr( args: Rc>>, inferred: Option>, callee_is_function_value: bool, + call_target: Rc, registry: Rc>>, scope: Rc, depth: i64, @@ -20993,7 +21009,13 @@ pub fn emit_typed_call_expr( emit_info: Rc, ) -> String { { - let call_str = if (func.clone() == "empty_map".to_string()) { + let target_is_runtime = match (*call_target.clone()).clone() { + CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: _, .. + } => true, + _ => false, + }; + let call_str = if (target_is_runtime.clone() && (func.clone() == "empty_map".to_string())) { match inferred.clone().as_deref().cloned() { Some(InferredNode::Resolved { node: ret_type, .. }) => { let kv_type_str = rust_empty_map_kv_type_str( @@ -21021,7 +21043,7 @@ pub fn emit_typed_call_expr( ), } } else { - if (func.clone() == "empty_set".to_string()) { + if (target_is_runtime.clone() && (func.clone() == "empty_set".to_string())) { match inferred.clone().as_deref().cloned() { Some(InferredNode::Resolved { node: ret_type, .. }) => { emit_rust_empty_set_expr( @@ -21038,6 +21060,7 @@ pub fn emit_typed_call_expr( func.clone(), args.clone(), callee_is_function_value.clone(), + call_target.clone(), registry.clone(), scope.clone(), depth.clone(), @@ -21047,7 +21070,13 @@ pub fn emit_typed_call_expr( } }; if ((callee_is_function_value.clone() == false) - && rust_runtime_bridge_wraps_collection_result_in_rc(func.clone())) + && match (*call_target.clone()).clone() { + CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: primitive_name, + .. + } => rust_runtime_bridge_wraps_collection_result_in_rc(primitive_name.clone()), + _ => false, + }) { rust_shared_wrap_ctor(call_str.clone()) } else { @@ -21227,6 +21256,7 @@ pub fn emit_typed_call( func: String, args: Rc>>, callee_is_function_value: bool, + call_target: Rc, registry: Rc>>, scope: Rc, depth: i64, @@ -21245,7 +21275,13 @@ pub fn emit_typed_call( emit_info.clone(), ); } - if (func.clone() == "get".to_string()) { + let target_is_runtime = match (*call_target.clone()).clone() { + CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: _, .. + } => true, + _ => false, + }; + if (target_is_runtime.clone() && (func.clone() == "get".to_string())) { { let get_args = order_typed_call_args(args.clone(), func.clone(), scope.clone()); let get_list = get_args.clone().first().cloned(); @@ -21289,7 +21325,7 @@ pub fn emit_typed_call( return get_result; } } - if (func.clone() == "with".to_string()) { + if (target_is_runtime.clone() && (func.clone() == "with".to_string())) { { let with_args = order_typed_call_args(args.clone(), func.clone(), scope.clone()); if ((with_args.clone().len() as i64) == 0) { @@ -21392,7 +21428,7 @@ pub fn emit_typed_call( } } } - if (func.clone() == "to_string".to_string()) { + if (target_is_runtime.clone() && (func.clone() == "to_string".to_string())) { { let to_string_args = order_typed_call_args(args.clone(), func.clone(), scope.clone()); @@ -21417,7 +21453,7 @@ pub fn emit_typed_call( return ts_result; } } - if (func.clone() == "utf8_decode_bytes".to_string()) { + if (target_is_runtime.clone() && (func.clone() == "utf8_decode_bytes".to_string())) { { let decode_args = order_typed_call_args(args.clone(), func.clone(), scope.clone()); let decode_result = match decode_args.clone().first().cloned() { @@ -21427,7 +21463,7 @@ pub fn emit_typed_call( return decode_result; } } - if (func.clone() == "discriminant".to_string()) { + if (target_is_runtime.clone() && (func.clone() == "discriminant".to_string())) { { let disc_args = order_typed_call_args(args.clone(), func.clone(), scope.clone()); let disc_result = match disc_args.clone().first().cloned() { @@ -21447,7 +21483,17 @@ pub fn emit_typed_call( } } let ordered_args = order_typed_call_args(args.clone(), func.clone(), scope.clone()); - let callee = lookup_item(registry.clone(), qualified_last_segment(func.clone())); + let callee = match (*call_target.clone()).clone() { + CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner, + decl_name: decl, + .. + } => lookup_item( + registry.clone(), + v1_rt::concat(v1_rt::concat(owner.clone(), ".".to_string()), decl.clone()), + ), + _ => None, + }; let filled_args = fill_default_args( ordered_args.clone(), callee.clone(), @@ -21457,10 +21503,17 @@ pub fn emit_typed_call( shared_types.clone(), emit_info.clone(), ); + let runtime_primitive_name = match (*call_target.clone()).clone() { + CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: primitive_name, + .. + } => primitive_name.clone(), + _ => "".to_string(), + }; let is_rt = ((callee_is_function_value.clone() == false) - && v1_rt::map_contains_key(&rt_functions(), func.clone())); - let is_rt_ref_map = ((callee_is_function_value.clone() == false) - && v1_rt::map_contains_key(&rt_ref_map_functions(), func.clone())); + && (runtime_primitive_name.clone() != "".to_string())); + let is_rt_ref_map = (is_rt.clone() + && v1_rt::map_contains_key(&rt_ref_map_functions(), runtime_primitive_name.clone())); let arg_strs = Rc::new({ let mut __result = Vec::new(); for pair in Rc::new( @@ -21553,7 +21606,7 @@ pub fn emit_typed_call( }; let all_args = v1_rt::concat(arg_strs.clone(), extra_args.clone()); let args_str = all_args.clone().join(&", ".to_string()); - let runtime_name = rust_runtime_bridge_name(func.clone()); + let runtime_name = rust_runtime_bridge_name(runtime_primitive_name.clone()); let si = scope.type_env.clone().source_indices.clone(); let callee_self_capture = if is_rt.clone() { false @@ -21575,7 +21628,38 @@ pub fn emit_typed_call( emit_ident(runtime_name.clone(), RenderTarget::Rust), ) } else { - emit_value_ref_ident(func.clone(), registry.clone(), emit_info.clone()) + match (*call_target.clone()).clone() { + CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner, + decl_name: decl, + .. + } => { + if (owner.clone() == scope.module_name.clone()) { + emit_ident(decl.clone(), RenderTarget::Rust) + } else { + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + "crate::".to_string(), + module_to_filename(owner.clone()), + ), + "::".to_string(), + ), + emit_ident(decl.clone(), RenderTarget::Rust), + ) + } + } + CallTargetIdentity::CallableTargetUndetermined => emit_error_expr( + "call target identity was not established before Rust emission".to_string(), + RenderTarget::Rust, + ), + CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: _, .. + } => emit_error_expr( + "runtime call target lost its bridge identity".to_string(), + RenderTarget::Rust, + ), + } }; let func_name = if callee_self_capture.clone() { v1_rt::concat(func_ident.clone(), ".clone()".to_string()) @@ -23618,6 +23702,7 @@ pub fn emit_rust_generic_method_call( receiver: Rc, args: Rc>>, result_type: Option>, + runtime_bridge: bool, registry: Rc>>, scope: Rc, depth: i64, @@ -23626,11 +23711,13 @@ pub fn emit_rust_generic_method_call( ) -> String { { let function_name = method_name.clone(); - if rust_receiver_has_callable_method_field( - receiver.clone(), - function_name.clone(), - scope.clone(), - ) { + if ((runtime_bridge.clone() == false) + && rust_receiver_has_callable_method_field( + receiver.clone(), + function_name.clone(), + scope.clone(), + )) + { { let recv_str = emit_typed_expr_base( receiver.clone(), @@ -23672,7 +23759,7 @@ pub fn emit_rust_generic_method_call( ) } } else { - if (v1_rt::map_contains_key(&rt_functions(), function_name.clone()) == false) { + if (runtime_bridge.clone() == false) { { let spec = language_spec(RenderTarget::Rust); apply_type_template1(spec.error_type_template.clone(), v1_rt::concat(v1_rt::concat("method ".to_string(), function_name.clone()), " is neither a resolved callable receiver field nor a registered v1_rt bridge function".to_string())) @@ -23997,6 +24084,7 @@ pub fn emit_typed_method_call( receiver.clone(), args.clone(), result_type.clone(), + true, registry.clone(), scope.clone(), depth.clone(), @@ -24113,6 +24201,7 @@ pub fn emit_typed_method_call( receiver.clone(), args.clone(), result_type.clone(), + true, registry.clone(), scope.clone(), depth.clone(), @@ -25707,21 +25796,17 @@ pub fn rust_receiver_has_callable_method_field( method_name: String, scope: Rc, ) -> bool { - if v1_rt::map_contains_key(&rt_functions(), method_name.clone()) { - false - } else { - { - let receiver_type = resolved_type(receiver.clone()); - let receiver_type_name = authored_name_at( - scope.type_env.clone().source_indices.clone(), - receiver_type.clone(), - ); - rust_record_field_needs_fn_rc( - scope.clone(), - receiver_type_name.clone(), - method_name.clone(), - ) - } + { + let receiver_type = resolved_type(receiver.clone()); + let receiver_type_name = authored_name_at( + scope.type_env.clone().source_indices.clone(), + receiver_type.clone(), + ); + rust_record_field_needs_fn_rc( + scope.clone(), + receiver_type_name.clone(), + method_name.clone(), + ) } } @@ -27786,6 +27871,7 @@ pub fn emit_rust_tco_non_self_call( f.clone(), frame.expr.clone().children.clone(), call_semantics_is_function_value(cs.clone()), + call_semantics_target(cs.clone()), registry.clone(), frame.scope.clone(), frame.depth.clone(), @@ -31746,6 +31832,7 @@ pub fn data_value_has_cross_refs(value: Rc) -> bool { ExprData::ExprVar { binding_kind: _, .. } => true, + ExprData::ExprCall { .. } => true, ExprData::ExprListLit => { let mut __found = false; for c in value.children.clone().iter().cloned() { diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index f3d6a951e14..e83261ee141 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -18,6 +18,7 @@ pub use crate::std_content_hash::{ content_hash_validate_lower_hex_length, }; pub use crate::std_content_hash::{ContentHash, Fnv1a64Structural}; +pub use crate::std_decl_ref::decl_ref; pub use crate::std_dissolution::DissolutionCondition; use crate::std_dissolution::DissolutionCondition::*; pub use crate::std_dissolution::{dissolution_description, unbound_dissolution}; @@ -38,6 +39,12 @@ pub use crate::std_interface_summary::{interface_summary_rollup, signature_contr pub use crate::std_interface_summary::{ExportEntry, ExportKind, InterfaceSummary}; pub use crate::std_node::{compiler_inductive_fields, compiler_recursive_types}; pub use crate::std_occurrence_identity::OccurrenceId; +pub use crate::std_primitive_projection::primitive_identity_runtime_name; +pub use crate::std_primitive_projection::primitive_projection_row_for_declaration; +pub use crate::std_primitive_projection::ProjectionFidelity; +use crate::std_primitive_projection::ProjectionFidelity::{ + DivergentProjection, HostRealizedSeam, ModeledProjection, +}; use crate::std_syntax::BinOp::Add; use crate::std_syntax::BinOp::{And, Div, Eq, Ge, Gt, Le, Lt, Mod, Mul, Ne, NullCoalesce, Or, Sub}; use crate::std_syntax::LiteralValue::LitStr; @@ -166,6 +173,9 @@ use crate::v1_std_core::AdmitCallersEntry::*; use crate::v1_std_core::CallSemantics::{ FunctionValueCallSemantics, LookupCallSemantics, PlainCallSemantics, }; +use crate::v1_std_core::CallTargetIdentity::{ + CallableTargetUndetermined, RuntimePrimitiveCall, SourceDeclarationCall, +}; use crate::v1_std_core::Cardinality::{CardOptional, Required}; use crate::v1_std_core::CompilerDiagnostic::{ AmbiguousReference, BareNoneNotAdmittedByFieldType, CallArgumentDuplicate, @@ -233,11 +243,11 @@ pub use crate::v1_std_core::{ expr_is_any_literal, expr_literal_symbol_optional, module_path_segments, }; pub use crate::v1_std_core::{ - AdmitCallersEntry, CallSemantics, Cardinality, CompilerDiagnostic, Connective, DeclRefCoords, - DeclaredFuncEnv, DeclaredFuncSig, ErrorNode, ExprData, ExprErrorKind, FieldAccessSpine, - FieldAccessStyle, FieldSummary, FieldValueShape, FrontierOccurrenceKey, InferredNode, - InternTable, MatchPattern, MethodSemantics, NewlineIndex, Node, ServiceConfigField, StringPart, - UnaryOpKind, VarBindingKind, + AdmitCallersEntry, CallSemantics, CallTargetIdentity, Cardinality, CompilerDiagnostic, + Connective, DeclRefCoords, DeclaredFuncEnv, DeclaredFuncSig, ErrorNode, ExprData, + ExprErrorKind, FieldAccessSpine, FieldAccessStyle, FieldSummary, FieldValueShape, + FrontierOccurrenceKey, InferredNode, InternTable, MatchPattern, MethodSemantics, NewlineIndex, + Node, ServiceConfigField, StringPart, UnaryOpKind, VarBindingKind, }; use crate::NonEmptyBTreeSet; use crate::NonEmptyVec; @@ -6259,40 +6269,53 @@ pub fn infer_expr_body( )) .clone() { - FuncSigLookup::FuncSigResolved { sig: fsig, .. } => { - match ((fsig.params.clone().len() as i64) == 0) { - true => ok_infer(make_named_expr_node( - name.clone(), - Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), - descent_evidence: None, - }), - Rc::new(vec![]), - Some(Rc::new(InferredNode::Resolved { - node: fsig.inferred.clone(), - })), - span.clone(), - span.clone(), - )), - false => ok_infer(make_named_expr_node( - name.clone(), - Rc::new(ExprData::ExprVar { - binding_kind: Some(Rc::new( - VarBindingKind::FunctionValueBinding, - )), - }), - Rc::new(vec![]), - Some(Rc::new(InferredNode::Resolved { - node: resolved_callable_type( - fsig.params.clone(), - fsig.inferred.clone(), - ), - })), - span.clone(), - span.clone(), - )), - } - } + FuncSigLookup::FuncSigResolved { + sig: fsig, + owner_module_path: sig_owner, + .. + } => match ((fsig.params.clone().len() as i64) == 0) { + true => ok_infer(make_named_expr_node( + name.clone(), + Rc::new(ExprData::ExprCall { + call_semantics: Some(Rc::new( + CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target( + scope.clone(), + name.clone(), + Rc::new(FuncSigLookup::FuncSigResolved { + sig: fsig.clone(), + owner_module_path: sig_owner.clone(), + }), + ), + }, + )), + descent_evidence: None, + }), + Rc::new(vec![]), + Some(Rc::new(InferredNode::Resolved { + node: fsig.inferred.clone(), + })), + span.clone(), + span.clone(), + )), + false => ok_infer(make_named_expr_node( + name.clone(), + Rc::new(ExprData::ExprVar { + binding_kind: Some(Rc::new( + VarBindingKind::FunctionValueBinding, + )), + }), + Rc::new(vec![]), + Some(Rc::new(InferredNode::Resolved { + node: resolved_callable_type( + fsig.params.clone(), + fsig.inferred.clone(), + ), + })), + span.clone(), + span.clone(), + )), + }, FuncSigLookup::FuncSigAmbiguous { candidates: ambiguous_fn_candidates, .. @@ -6948,9 +6971,15 @@ pub fn infer_expr_body( typed: make_named_expr_node( func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some( - CallSemantics::PlainCallSemantics, - ), + call_semantics: Some(Rc::new( + CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target( + scope.clone(), + func_name.clone(), + call_sig_lookup.clone(), + ), + }, + )), descent_evidence: None, }), typed_arg_nodes.clone(), @@ -7266,11 +7295,16 @@ pub fn infer_expr_body( { { let bare_m = bare_map_node(); + let empty_map_call_semantics = Some(Rc::new(CallSemantics::PlainCallSemantics { + target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: "empty_map".to_string(), +}), +})); match expected.clone() { Some(exp) => if node_is_keyed_collection(exp.clone(), scope.type_env.clone().source_indices.clone()) { Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: empty_map_call_semantics.clone(), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { node: exp.clone(), @@ -7283,7 +7317,7 @@ pub fn infer_expr_body( match bare_m.clone() { Some(map_t) => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: empty_map_call_semantics.clone(), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { node: map_t.clone(), @@ -7292,7 +7326,7 @@ match bare_m.clone() { }), None => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: empty_map_call_semantics.clone(), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::CompilerError { message: "empty_map(): Map kernel container profile missing (compiler misconfigured)".to_string(), @@ -7306,7 +7340,7 @@ match bare_m.clone() { None => match bare_m.clone() { Some(map_t) => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: empty_map_call_semantics.clone(), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { node: map_t.clone(), @@ -7315,7 +7349,7 @@ match bare_m.clone() { }), None => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: empty_map_call_semantics.clone(), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::CompilerError { message: "empty_map(): Map kernel container profile missing (compiler misconfigured)".to_string(), @@ -7336,7 +7370,9 @@ match bare_m.clone() { Some(exp) => if node_is_set_collection(exp.clone(), scope.type_env.clone().source_indices.clone()) { Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target(scope.clone(), func_name.clone(), call_sig_lookup.clone()), +})), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { node: exp.clone(), @@ -7349,7 +7385,9 @@ match bare_m.clone() { match bare_s.clone() { Some(set_t) => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target(scope.clone(), func_name.clone(), call_sig_lookup.clone()), +})), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { node: set_t.clone(), @@ -7358,7 +7396,9 @@ match bare_s.clone() { }), None => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target(scope.clone(), func_name.clone(), call_sig_lookup.clone()), +})), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::CompilerError { message: "empty_set(): Set kernel container profile missing (compiler misconfigured)".to_string(), @@ -7372,7 +7412,9 @@ match bare_s.clone() { None => match bare_s.clone() { Some(set_t) => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target(scope.clone(), func_name.clone(), call_sig_lookup.clone()), +})), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { node: set_t.clone(), @@ -7381,7 +7423,9 @@ match bare_s.clone() { }), None => Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target(scope.clone(), func_name.clone(), call_sig_lookup.clone()), +})), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::CompilerError { message: "empty_set(): Set kernel container profile missing (compiler misconfigured)".to_string(), @@ -7409,9 +7453,22 @@ match bare_s.clone() { let call_semantics = if (func_name.clone() == "lookup".to_string()) { - Some(CallSemantics::LookupCallSemantics) + Some(Rc::new(CallSemantics::LookupCallSemantics { + target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: func_name.clone(), +}), +})) } else { - Some(CallSemantics::PlainCallSemantics) + Some(Rc::new( + CallSemantics::PlainCallSemantics { + target: + resolved_plain_call_target( + scope.clone(), + func_name.clone(), + call_sig_lookup.clone(), + ), + }, + )) }; Rc::new(InferResult { typed: make_named_expr_node( @@ -7473,9 +7530,11 @@ match bare_s.clone() { Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { call_semantics: Some(if callee_is_body_binding.clone() { - CallSemantics::FunctionValueCallSemantics + Rc::new(CallSemantics::FunctionValueCallSemantics) } else { - CallSemantics::PlainCallSemantics + Rc::new(CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target(scope.clone(), func_name.clone(), call_sig_lookup.clone()), +}) }), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { @@ -7536,7 +7595,9 @@ if ((call_ambiguity_cands.clone().len() as i64) > 0) { }; Rc::new(InferResult { typed: make_named_expr_node(func_name.clone(), Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), + call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { + target: resolved_plain_call_target(scope.clone(), func_name.clone(), call_sig_lookup.clone()), +})), descent_evidence: None, }), typed_arg_nodes.clone(), Some(Rc::new(InferredNode::Resolved { node: resolved_type.clone(), @@ -7580,27 +7641,15 @@ if ((call_ambiguity_cands.clone().len() as i64) > 0) { v1_rt::concat(recv_spine.dotted.clone(), ".".to_string()), method_name.clone(), ); - match symbol_index_lookup( - scope.type_env.clone().symbol_index.clone(), - dotted.clone(), - ) { - None => None, - Some(_) => Some(infer_expr( - make_named_expr_node( - dotted.clone(), - Rc::new(ExprData::ExprCall { - call_semantics: Some(CallSemantics::PlainCallSemantics), - descent_evidence: None, - }), - mc_args.clone(), - None, - span.clone(), - kernel_span(dotted.clone()), - ), - scope.clone(), - expected.clone(), - )), - } + match symbol_index_lookup(scope.type_env.clone().symbol_index.clone(), dotted.clone()) { + None => None, + Some(_) => Some(infer_expr(make_named_expr_node(dotted.clone(), Rc::new(ExprData::ExprCall { + call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { + target: Rc::new(CallTargetIdentity::CallableTargetUndetermined), +})), + descent_evidence: None, +}), mc_args.clone(), None, span.clone(), kernel_span(dotted.clone())), scope.clone(), expected.clone())), +} } } } @@ -9276,6 +9325,117 @@ pub fn call_locals_shadow_note() -> String { CACHED.with(|c: &String| c.clone()) } +pub fn resolved_call_target_identity_note() -> String { + thread_local! { + static CACHED: String = { + "A call is resolved once, where its lexical scope is available, and emission consumes that exact result. RuntimePrimitiveCall is produced only by builtin resolution or when std.primitive_projection says THIS exact declaration is a HostRealizedSeam/ModeledProjection of the primitive. SourceDeclarationCall is retained for ordinary declarations and for DivergentProjection (v2.std.collection map_get is the canonical divergent row). The authored leaf spelling never participates in target selection after this point. CallableTargetUndetermined is a refusal-bearing residue, not permission for emission to retry name lookup. This closes the authority-substitution class in which v2.std.algebra contains resolved correctly but 05_emit_rust re-decided it as the unrelated two-String v1_rt substring primitive. The same identity is consumed by free-call bridge selection, by-reference lowering, and result wrapping; source_visible_names would only let emission repeat resolution and is deliberately not the mechanism.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +pub fn empty_map_call_target_proof_note() -> String { + thread_local! { + static CACHED: String = { + "empty_map is intentionally absent from builtin_function_registry because its return type comes from the expected Map shape. Reaching the dedicated empty_map inference branch is therefore both the keyed-container type proof and the runtime-primitive target proof; that branch records RuntimePrimitiveCall directly instead of asking the generic signature lookup to reconstruct an identity it does not own.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +pub fn resolved_plain_call_target( + scope: Rc, + func_name: String, + sig_lookup: Rc, +) -> Rc { + match (*sig_lookup.clone()).clone() { + FuncSigLookup::FuncSigResolved { + owner_module_path, .. + } => resolved_declaration_call_target( + owner_module_path.clone(), + qualified_last_segment(func_name.clone()), + func_name.clone(), + ), + FuncSigLookup::FuncSigUnresolved => { + if (infer_builtin_call_type(func_name.clone()) != None) { + Rc::new(CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: func_name.clone(), + }) + } else { + Rc::new(CallTargetIdentity::CallableTargetUndetermined) + } + } + FuncSigLookup::FuncSigAmbiguous { candidates: _, .. } => { + Rc::new(CallTargetIdentity::CallableTargetUndetermined) + } + } +} + +pub fn resolved_call_target_from_declaration_lookup( + declaration_lookup: Rc, + func_name: String, +) -> Rc { + match (*declaration_lookup.clone()).clone() { + ConstructorDeclarationLookup::ExactConstructorDeclaration { identity, .. } => { + resolved_declaration_call_target( + identity.owner_module_path.clone(), + identity.decl_name.clone(), + func_name.clone(), + ) + } + ConstructorDeclarationLookup::AdmissionBearingDeclarationUnavailable { + identity, .. + } => resolved_declaration_call_target( + identity.owner_module_path.clone(), + identity.decl_name.clone(), + func_name.clone(), + ), + ConstructorDeclarationLookup::NotAdmissionBearingReference => { + if (infer_builtin_call_type(func_name.clone()) != None) { + Rc::new(CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: func_name.clone(), + }) + } else { + Rc::new(CallTargetIdentity::CallableTargetUndetermined) + } + } + } +} + +pub fn resolved_declaration_call_target( + owner_module_path: String, + decl_name: String, + func_name: String, +) -> Rc { + match primitive_projection_row_for_declaration(decl_ref( + owner_module_path.clone(), + decl_name.clone(), + )) { + Some(row) => match (*row.fidelity.clone()).clone() { + ProjectionFidelity::HostRealizedSeam => { + Rc::new(CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: primitive_identity_runtime_name(row.primitive.clone()), + }) + } + ProjectionFidelity::ModeledProjection => { + Rc::new(CallTargetIdentity::RuntimePrimitiveCall { + primitive_name: primitive_identity_runtime_name(row.primitive.clone()), + }) + } + ProjectionFidelity::DivergentProjection { divergence: _, .. } => { + Rc::new(CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner_module_path.clone(), + decl_name: decl_name.clone(), + }) + } + }, + None => Rc::new(CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner_module_path.clone(), + decl_name: decl_name.clone(), + }), + } +} + pub fn peel_alias_fixpoint_guard_note() -> String { thread_local! { static CACHED: String = { @@ -20464,6 +20624,124 @@ pub fn build_imported_variants( ) } +pub fn selective_func_env_view( + env: Rc, + names: Rc>, +) -> Rc { + { + let selected = names.iter().cloned().fold( + v1_rt::rc_empty_map::>(), + |acc: Rc>>, name: String| match v1_rt::map_get( + &env.local.clone(), + name.clone(), + ) { + Some(sig) => v1_rt::rc_map_insert(acc.clone(), name.clone(), sig.clone()), + None => acc.clone(), + }, + ); + Rc::new(ResolvedFuncEnv { + name: env.name.clone(), + local: selected.clone(), + parents: Rc::new(vec![]), + }) + } +} + +pub fn func_env_views_for_import( + parent: Rc, + is_all: bool, + specific_names: Rc>, +) -> Rc>> { + if is_all.clone() { + Rc::new(vec![parent.clone()]) + } else { + Rc::new({ + let mut __result = Vec::new(); + for env in v1_rt::concat(Rc::new(vec![parent.clone()]), parent.parents.clone()) + .iter() + .cloned() + { + __result.push(selective_func_env_view(env.clone(), specific_names.clone())); + } + __result + }) + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct FuncEnvViewMerge { + pub by_owner: Rc>>, + pub owner_order: Rc>, +} + +pub fn merge_func_sig_maps( + base: Rc>>, + incoming: Rc>>, +) -> Rc>> { + Rc::new(v1_rt::map_keys(&incoming)).iter().cloned().fold( + base.clone(), + |acc: Rc>>, name: String| match v1_rt::map_get( + &incoming, + name.clone(), + ) { + Some(sig) => v1_rt::rc_map_insert(acc.clone(), name.clone(), sig.clone()), + None => acc.clone(), + }, + ) +} + +pub fn merge_func_env_views_by_owner( + views: Rc>>, +) -> Rc>> { + { + let merged = views.iter().cloned().fold( + Rc::new(FuncEnvViewMerge { + by_owner: v1_rt::rc_empty_map::>(), + owner_order: Rc::new(vec![]), + }), + |acc: Rc, view: Rc| match v1_rt::map_get( + &acc.by_owner.clone(), + view.name.clone(), + ) { + Some(existing) => Rc::new(FuncEnvViewMerge { + by_owner: v1_rt::rc_map_insert( + acc.by_owner.clone(), + view.name.clone(), + Rc::new(ResolvedFuncEnv { + name: view.name.clone(), + local: merge_func_sig_maps(existing.local.clone(), view.local.clone()), + parents: Rc::new(vec![]), + }), + ), + owner_order: acc.owner_order.clone(), + }), + None => Rc::new(FuncEnvViewMerge { + by_owner: v1_rt::rc_map_insert( + acc.by_owner.clone(), + view.name.clone(), + view.clone(), + ), + owner_order: v1_rt::rc_list_push(acc.owner_order.clone(), view.name.clone()), + }), + }, + ); + Rc::new({ + let mut __result = Vec::new(); + for owner in merged.owner_order.clone().iter().cloned() { + __result.extend( + (*match v1_rt::map_get(&merged.by_owner.clone(), owner.clone()) { + Some(env) => Rc::new(vec![env.clone()]), + None => Rc::new(vec![]), + }) + .iter() + .cloned(), + ); + } + __result + }) + } +} + pub fn build_module_context( contributions: Rc>>, parent_index: Rc>>, @@ -20572,12 +20850,16 @@ pub fn build_module_context( ), v1_rt::rc_map_merge(census_scope.svc_locals.clone(), local.svc_locals.clone()), ); - let parent_envs = Rc::new({ + let parent_envs = merge_func_env_views_by_owner(Rc::new({ let mut __result = Vec::new(); for imp in resolved_imports.iter().cloned() { __result.extend( (*match v1_rt::map_get(&parent_index, imp.module_path.clone()) { - Some(typed_parent) => Rc::new(vec![typed_parent.func_env.clone()]), + Some(typed_parent) => func_env_views_for_import( + typed_parent.func_env.clone(), + imp.is_all.clone(), + imp.specific_names.clone(), + ), None => Rc::new(vec![]), }) .iter() @@ -20585,7 +20867,7 @@ pub fn build_module_context( ); } __result - }); + })); let resolve_result = resolve_func_sigs( local.func_sigs.clone(), parent_envs.clone(), @@ -22251,7 +22533,7 @@ pub fn rewire_func_env_parent_links( let mut __result = Vec::new(); for m in modules.iter().cloned() { __result.push({ - let parents = Rc::new({ + let parents = merge_func_env_views_by_owner(Rc::new({ let mut __result = Vec::new(); for imp in module_imports(m.module.clone()).iter().cloned() { __result.extend( @@ -22259,7 +22541,14 @@ pub fn rewire_func_env_parent_links( let path = import_module_path_at(imp.clone(), source_indices.clone()); match v1_rt::map_get(&index, path.clone()) { - Some(parent) => Rc::new(vec![parent.func_env.clone()]), + Some(parent) => func_env_views_for_import( + parent.func_env.clone(), + import_is_all(imp.clone()), + import_specific_names_at( + imp.clone(), + source_indices.clone(), + ), + ), None => Rc::new(vec![]), } }) @@ -22268,7 +22557,7 @@ pub fn rewire_func_env_parent_links( ); } __result - }); + })); Rc::new(TypedModule { module: m.module.clone(), items: m.items.clone(), diff --git a/src/v1/stage0/src/v1_compiler_infer_lookup.rs b/src/v1/stage0/src/v1_compiler_infer_lookup.rs index 5c2dae6cc29..a5087301783 100644 --- a/src/v1/stage0/src/v1_compiler_infer_lookup.rs +++ b/src/v1/stage0/src/v1_compiler_infer_lookup.rs @@ -104,9 +104,14 @@ pub fn lookup_func_sig( Rc::new(FuncSigLookup::FuncSigUnresolved) } else { match (*lookup_resolved_sig(func_env.clone(), name.clone())).clone() { - FuncSigLookup::FuncSigResolved { sig: sig, .. } => { - Rc::new(FuncSigLookup::FuncSigResolved { sig: sig.clone() }) - } + FuncSigLookup::FuncSigResolved { + sig, + owner_module_path: owner, + .. + } => Rc::new(FuncSigLookup::FuncSigResolved { + sig: sig.clone(), + owner_module_path: owner.clone(), + }), FuncSigLookup::FuncSigAmbiguous { candidates: cands, .. } => Rc::new(FuncSigLookup::FuncSigAmbiguous { @@ -121,7 +126,7 @@ pub fn lookup_func_sig( pub fn func_sig_if_resolved(lookup: Rc) -> Option> { match (*lookup.clone()).clone() { - FuncSigLookup::FuncSigResolved { sig: sig, .. } => Some(sig.clone()), + FuncSigLookup::FuncSigResolved { sig, .. } => Some(sig.clone()), FuncSigLookup::FuncSigUnresolved => None, FuncSigLookup::FuncSigAmbiguous { candidates: _, .. } => None, } @@ -376,6 +381,7 @@ pub fn func_sig_from_global_bare(type_env: Rc, name: String) -> Rc( ), }), + owner_module_path: bd.owner_module_path.clone(), }) } else { { @@ -408,6 +414,7 @@ pub fn func_sig_from_global_bare(type_env: Rc, name: String) -> Rc( ), }), + owner_module_path: bd.owner_module_path.clone(), }) } } diff --git a/src/v1/stage0/src/v1_compiler_infer_sigs.rs b/src/v1/stage0/src/v1_compiler_infer_sigs.rs index 029e28cf82f..f6c20b8144a 100644 --- a/src/v1/stage0/src/v1_compiler_infer_sigs.rs +++ b/src/v1/stage0/src/v1_compiler_infer_sigs.rs @@ -124,7 +124,7 @@ pub struct ParentSigScan { pub fn func_sig_lookup_outcome_note() -> String { thread_local! { static CACHED: String = { - "namespace-resolution-design.md 13 / 8 step 1, fn path: ResolvedFuncSig? overloaded Absent as 'keep looking' (the census fallback fires on it), so a refusal had nowhere to go — the first-hit over func_env.parents was the fn silent-pick class (fn_parent_first_hit) with NO refusal arm at all. FuncSigLookup is the 3-state outcome: FuncSigResolved binds, FuncSigUnresolved means genuinely-no-sig (census fallback may still run), FuncSigAmbiguous carries the full candidate list and REFUSES — it never falls through to a fallback. Under ImportScoped (host bracket false) the first-hit behavior remains until the downstream production flip; under NamespaceOnlyY exactly-one match across the flat parent closure resolves, two-plus refuses through module_path_owner_binding_decide. Own-module local hit stays first on both arms.".to_string() + "namespace-resolution-design.md 13 / 8 step 1, fn path: ResolvedFuncSig? overloaded Absent as 'keep looking' (the census fallback fires on it), so a refusal had nowhere to go — the first-hit over func_env.parents was the fn silent-pick class (fn_parent_first_hit) with NO refusal arm at all. FuncSigLookup is the 3-state outcome: FuncSigResolved binds the signature AND its exact owner module, FuncSigUnresolved means genuinely-no-sig (census fallback may still run), FuncSigAmbiguous carries the full candidate list and REFUSES — it never falls through to a fallback. The owner is part of resolution, not reconstructible from admission lookup: emission target identity consumes it directly after inference. Under ImportScoped (host bracket false) the first-hit behavior remains until the downstream production flip; under NamespaceOnlyY exactly-one match across the flat parent closure resolves, two-plus refuses through module_path_owner_binding_decide. Own-module local hit stays first on both arms.".to_string() }; } CACHED.with(|c: &String| c.clone()) @@ -133,9 +133,14 @@ pub fn func_sig_lookup_outcome_note() -> String { #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(tag = "_variant")] pub enum FuncSigLookup { - FuncSigResolved { sig: Rc }, + FuncSigResolved { + sig: Rc, + owner_module_path: String, + }, FuncSigUnresolved, - FuncSigAmbiguous { candidates: Rc> }, + FuncSigAmbiguous { + candidates: Rc>, + }, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -173,9 +178,12 @@ pub fn lookup_resolved_sig_unique_across_parents( ModulePathBindingProjection::ModulePathBindingMiss => { Rc::new(FuncSigLookup::FuncSigUnresolved) } - ModulePathBindingProjection::ModulePathBindingHit { owner: _, .. } => { + ModulePathBindingProjection::ModulePathBindingHit { owner: owner, .. } => { match scan.first_sig.clone() { - Some(sig) => Rc::new(FuncSigLookup::FuncSigResolved { sig: sig.clone() }), + Some(sig) => Rc::new(FuncSigLookup::FuncSigResolved { + sig: sig.clone(), + owner_module_path: owner.clone(), + }), None => Rc::new(FuncSigLookup::FuncSigUnresolved), } } @@ -188,10 +196,16 @@ pub fn lookup_resolved_sig_unique_across_parents( } } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ResolvedSigWithOwner { + pub sig: Rc, + pub owner_module_path: String, +} + pub fn lookup_resolved_sig_with_telemetry( env: Rc, name: String, -) -> Option> { +) -> Option> { { let scan = env.parents.clone().iter().cloned().fold( Rc::new(ParentSigScan { @@ -230,13 +244,25 @@ pub fn lookup_resolved_sig_with_telemetry( None => {} } } - scan.sig.clone() + match scan.sig.clone() { + Some(sig) => match scan.first_parent.clone() { + Some(owner) => Some(Rc::new(ResolvedSigWithOwner { + sig: sig.clone(), + owner_module_path: owner.clone(), + })), + None => None, + }, + None => None, + } } } pub fn lookup_resolved_sig(env: Rc, name: String) -> Rc { match v1_rt::map_get(&env.local.clone(), name.clone()) { - Some(sig) => Rc::new(FuncSigLookup::FuncSigResolved { sig: sig.clone() }), + Some(sig) => Rc::new(FuncSigLookup::FuncSigResolved { + sig: sig.clone(), + owner_module_path: env.name.clone(), + }), None => { if v1_rt::name_resolution_policy_is_namespace_only() { lookup_resolved_sig_unique_across_parents(env.clone(), name.clone()) @@ -246,17 +272,26 @@ pub fn lookup_resolved_sig(env: Rc, name: String) -> Rc>, p: Rc| match acc - .clone() - { - Some(sig) => Some(sig.clone()), - None => v1_rt::map_get(&p.local.clone(), name.clone()), + none_resolved_sig_with_owner(), + |acc: Option>, p: Rc| { + match acc.clone() { + Some(found) => Some(found.clone()), + None => match v1_rt::map_get(&p.local.clone(), name.clone()) { + Some(sig) => Some(Rc::new(ResolvedSigWithOwner { + sig: sig.clone(), + owner_module_path: p.name.clone(), + })), + None => None, + }, + } }, ) }; match first_hit.clone() { - Some(sig) => Rc::new(FuncSigLookup::FuncSigResolved { sig: sig.clone() }), + Some(found) => Rc::new(FuncSigLookup::FuncSigResolved { + sig: found.sig.clone(), + owner_module_path: found.owner_module_path.clone(), + }), None => Rc::new(FuncSigLookup::FuncSigUnresolved), } } @@ -265,7 +300,7 @@ pub fn lookup_resolved_sig(env: Rc, name: String) -> Rc Option> { +pub fn none_resolved_sig_with_owner() -> Option> { None } diff --git a/src/v1/stage0/src/v1_compiler_infer_types.rs b/src/v1/stage0/src/v1_compiler_infer_types.rs index 4906512027c..79af8e55257 100644 --- a/src/v1/stage0/src/v1_compiler_infer_types.rs +++ b/src/v1/stage0/src/v1_compiler_infer_types.rs @@ -647,22 +647,43 @@ pub fn make_kernel_record_type(type_name: String, fields: Rc>>) -> } pub fn make_container_type(kind_name: String, element: Rc) -> Rc { - match container_param_name(kind_name.clone(), 0) { - Some(param_name) => Rc::new(KernelTypeBuild { - ty: Rc::new(Node { - name: kind_name.clone(), - span: kernel_span(kind_name.clone()), - ident_span: Some(kernel_span(kind_name.clone())), - children: Rc::new(vec![Rc::new(Node { - name: param_name.clone(), - span: kernel_span(param_name.clone()), - ident_span: Some(kernel_span(param_name.clone())), - children: Rc::new(vec![]), + if !is_kernel_type(kind_name.clone()) { + Rc::new(KernelTypeBuild { + ty: nominal_type_ref(kind_name.clone()), + diagnostics: Rc::new(vec![]), + }) + } else { + match container_param_name(kind_name.clone(), 0) { + Some(param_name) => Rc::new(KernelTypeBuild { + ty: Rc::new(Node { + name: kind_name.clone(), + span: kernel_span(kind_name.clone()), + ident_span: Some(kernel_span(kind_name.clone())), + children: Rc::new(vec![Rc::new(Node { + name: param_name.clone(), + span: kernel_span(param_name.clone()), + ident_span: Some(kernel_span(param_name.clone())), + children: Rc::new(vec![]), + connective: Connective::NoConnective, + params: Rc::new(vec![]), + inferred: Some(Rc::new(InferredNode::Resolved { + node: element.clone(), + })), + return_cardinality: Cardinality::Required, + uses: Rc::new(vec![]), + body: None, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + })]), connective: Connective::NoConnective, params: Rc::new(vec![]), - inferred: Some(Rc::new(InferredNode::Resolved { - node: element.clone(), - })), + inferred: None, return_cardinality: Cardinality::Required, uses: Rc::new(vec![]), body: None, @@ -674,30 +695,16 @@ pub fn make_container_type(kind_name: String, element: Rc) -> Rc Rc::new(KernelTypeBuild { - ty: missing_kernel_container_profile_type(kind_name.clone()), - diagnostics: Rc::new(vec![kernel_container_profile_miss_diagnostic( - kind_name.clone(), - )]), - }), + None => Rc::new(KernelTypeBuild { + ty: missing_kernel_container_profile_type(kind_name.clone()), + diagnostics: Rc::new(vec![kernel_container_profile_miss_diagnostic( + kind_name.clone(), + )]), + }), + } } } @@ -1638,17 +1645,24 @@ pub fn apply_type_substitution( source_indices.clone(), receiver.clone(), )); - match container_param_name(rname.clone(), 0) { - Some(n) => Rc::new(KernelTypeBuild { - ty: type_variable_node(n.clone()), + if !is_kernel_type(rname.clone()) { + Rc::new(KernelTypeBuild { + ty: receiver.clone(), diagnostics: Rc::new(vec![]), - }), - None => Rc::new(KernelTypeBuild { - ty: missing_kernel_container_profile_type(rname.clone()), - diagnostics: Rc::new(vec![ - kernel_container_profile_miss_diagnostic(rname.clone()), - ]), - }), + }) + } else { + match container_param_name(rname.clone(), 0) { + Some(n) => Rc::new(KernelTypeBuild { + ty: type_variable_node(n.clone()), + diagnostics: Rc::new(vec![]), + }), + None => Rc::new(KernelTypeBuild { + ty: missing_kernel_container_profile_type(rname.clone()), + diagnostics: Rc::new(vec![ + kernel_container_profile_miss_diagnostic(rname.clone()), + ]), + }), + } } } }, @@ -1669,17 +1683,24 @@ pub fn apply_type_substitution( source_indices.clone(), receiver.clone(), )); - match container_param_name(rname.clone(), 0) { - Some(n) => Rc::new(KernelTypeBuild { - ty: type_variable_node(n.clone()), + if !is_kernel_type(rname.clone()) { + Rc::new(KernelTypeBuild { + ty: receiver.clone(), diagnostics: Rc::new(vec![]), - }), - None => Rc::new(KernelTypeBuild { - ty: missing_kernel_container_profile_type(rname.clone()), - diagnostics: Rc::new(vec![ - kernel_container_profile_miss_diagnostic(rname.clone()), - ]), - }), + }) + } else { + match container_param_name(rname.clone(), 0) { + Some(n) => Rc::new(KernelTypeBuild { + ty: type_variable_node(n.clone()), + diagnostics: Rc::new(vec![]), + }), + None => Rc::new(KernelTypeBuild { + ty: missing_kernel_container_profile_type(rname.clone()), + diagnostics: Rc::new(vec![ + kernel_container_profile_miss_diagnostic(rname.clone()), + ]), + }), + } } } }, @@ -1706,17 +1727,24 @@ pub fn apply_type_substitution( source_indices.clone(), receiver.clone(), )); - match container_param_name(rname.clone(), 1) { - Some(n) => Rc::new(KernelTypeBuild { - ty: type_variable_node(n.clone()), + if !is_kernel_type(rname.clone()) { + Rc::new(KernelTypeBuild { + ty: receiver.clone(), diagnostics: Rc::new(vec![]), - }), - None => Rc::new(KernelTypeBuild { - ty: missing_kernel_container_profile_type(rname.clone()), - diagnostics: Rc::new(vec![ - kernel_container_profile_miss_diagnostic(rname.clone()), - ]), - }), + }) + } else { + match container_param_name(rname.clone(), 1) { + Some(n) => Rc::new(KernelTypeBuild { + ty: type_variable_node(n.clone()), + diagnostics: Rc::new(vec![]), + }), + None => Rc::new(KernelTypeBuild { + ty: missing_kernel_container_profile_type(rname.clone()), + diagnostics: Rc::new(vec![ + kernel_container_profile_miss_diagnostic(rname.clone()), + ]), + }), + } } } }, diff --git a/src/v1/stage0/src/v1_std_core.rs b/src/v1/stage0/src/v1_std_core.rs index 38cf6cc554f..0d5f29e55df 100644 --- a/src/v1/stage0/src/v1_std_core.rs +++ b/src/v1/stage0/src/v1_std_core.rs @@ -3,6 +3,7 @@ use self::AdmitCallersEntry::*; use self::CallSemantics::*; +use self::CallTargetIdentity::*; use self::Cardinality::*; use self::CompilerDiagnostic::*; use self::Connective::*; @@ -227,15 +228,35 @@ impl VarBindingKind { } } -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, -)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum CallTargetIdentity { + RuntimePrimitiveCall { + primitive_name: String, + }, + SourceDeclarationCall { + owner_module_path: String, + decl_name: String, + }, + CallableTargetUndetermined, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(tag = "_variant")] pub enum CallSemantics { - PlainCallSemantics, - LookupCallSemantics, + PlainCallSemantics { target: Rc }, + LookupCallSemantics { target: Rc }, FunctionValueCallSemantics, } +impl CallSemantics { + pub fn target(&self) -> Rc { + match self { + CallSemantics::PlainCallSemantics { target: __val, .. } => __val.clone(), + CallSemantics::LookupCallSemantics { target: __val, .. } => __val.clone(), + CallSemantics::FunctionValueCallSemantics => panic!("no target on unit variant"), + } + } +} #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(tag = "_variant")] @@ -283,7 +304,7 @@ pub enum ExprData { summary: Option>, }, ExprCall { - call_semantics: Option, + call_semantics: Option>, descent_evidence: Option>>>, }, ExprMethodCall { @@ -4530,12 +4551,6 @@ pub struct PlainValue; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct OptionalValue; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct PlainCallSemantics; -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct LookupCallSemantics; -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct FunctionValueCallSemantics; -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct ParseRecoveryError; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct SemanticExprError; diff --git a/src/v1/stage0/src/v1_tests_claim_resolved_call_emission_identity_internal_witness_test.rs b/src/v1/stage0/src/v1_tests_claim_resolved_call_emission_identity_internal_witness_test.rs new file mode 100644 index 00000000000..0a0cf1cdd64 --- /dev/null +++ b/src/v1/stage0/src/v1_tests_claim_resolved_call_emission_identity_internal_witness_test.rs @@ -0,0 +1,126 @@ +// Generated by v1 compiler -- do not edit. +// Source module: v1.tests.claim.resolved_call_emission_identity_internal_witness_test + +pub use crate::std_induction::SubValueRelation; +use crate::std_induction::SubValueRelation::*; +pub use crate::v1_compiler_infer::{ + merge_func_env_views_by_owner, resolved_call_target_from_declaration_lookup, + selective_func_env_view, +}; +use crate::v1_compiler_infer_lookup::ConstructorDeclarationLookup::AdmissionBearingDeclarationUnavailable; +use crate::v1_compiler_infer_lookup::DeclarationLookupFailure::DeclarationNotIndexedAtQualifiedName; +pub use crate::v1_compiler_infer_lookup::{ + ConstructorDeclarationLookup, DeclarationLookupFailure, ExactDeclarationIdentity, +}; +pub use crate::v1_compiler_infer_sigs::{ResolvedFuncEnv, ResolvedFuncSig}; +use crate::v1_rt; +use crate::v1_rt::{VecCompat, VecJoin}; +pub use crate::v1_std_core::error_type; +pub use crate::v1_std_core::CallTargetIdentity; +use crate::v1_std_core::CallTargetIdentity::SourceDeclarationCall; +use crate::NonEmptyBTreeSet; +use crate::NonEmptyVec; +use im::{vector as vec, HashMap, OrdSet as BTreeSet, Vector as Vec}; +use std::rc::Rc; + +pub fn resolved_call_emission_identity_internal_witness_note() -> String { + thread_local! { + static CACHED: String = { + "DECLARED RUNG: white-box authoring-time evidence, measured 2026-08-24, for three compiler-internal call-identity decisions: AdmissionBearingDeclarationUnavailable retains its exact target identity, a selective parent view excludes unlisted locals, and overlapping selective views of one real owner union their admitted locals. These rows cannot be expressed through the required floor's dag plus src/v2 source-root envelope. They were split from test.claim.resolved_call_emission_identity_witness_test after required CI correctly refused its direct v1.compiler imports: dag/test is an executing home only for the eight black-box compile_dag_rust_emit_check controls retained there. This src/v1 file is parse-checked and all three rows passed when run directly during authoring, but no mechanism re-executes them: a regression in any of these three internal behaviours is SILENT. Direct execution proves only that the assertions held on the measurement date, never that CI keeps them true. None has an honest black-box discriminator today: global-bare fallback masks the two parent-view behaviours after their owned layer, while the unavailable-declaration state is not constructible from source. Re-homing these helpers into dag/std would invert the seed boundary by making compiler internals substrate API. NEXT-RUNG TRIGGER: a CI-visible harness that can reach v1.compiler internals without re-exporting them across the seed boundary, or a dag-reachable behavioural surface that can construct these exact internal states. dissolve-on: all three rows gain an enrolled behavioural home.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + +pub fn w_unavailable_declaration_retains_exact_call_identity() -> bool { + (resolved_call_target_from_declaration_lookup( + Rc::new( + ConstructorDeclarationLookup::AdmissionBearingDeclarationUnavailable { + identity: Rc::new(ExactDeclarationIdentity { + owner_module_path: "test.fixture.owner".to_string(), + decl_name: "declared_call".to_string(), + }), + cause: Rc::new( + DeclarationLookupFailure::DeclarationNotIndexedAtQualifiedName { + qualified_name: "test.fixture.owner.declared_call".to_string(), + }, + ), + }, + ), + "declared_call".to_string(), + ) == Rc::new(CallTargetIdentity::SourceDeclarationCall { + owner_module_path: "test.fixture.owner".to_string(), + decl_name: "declared_call".to_string(), + })) +} + +pub fn fixture_sig() -> Rc { + Rc::new(ResolvedFuncSig { + name: "fixture".to_string(), + params: Rc::new(vec![]), + inferred: error_type(), + is_async: false, + output_provenance: Rc::new(vec![]), + variant_provenance: v1_rt::rc_empty_map::< + String, + Rc>>>>, + >(), + }) +} + +pub fn w_selective_function_import_refuses_unlisted_parent_local() -> bool { + { + let sig = fixture_sig(); + let parent = Rc::new(ResolvedFuncEnv { + name: "test.fixture.function_import_surface_provider".to_string(), + local: v1_rt::rc_map_insert( + v1_rt::rc_map_insert( + v1_rt::rc_empty_map::>(), + "imported_fn".to_string(), + sig.clone(), + ), + "hidden_fn".to_string(), + sig.clone(), + ), + parents: Rc::new(vec![]), + }); + let selected = + selective_func_env_view(parent.clone(), Rc::new(vec!["imported_fn".to_string()])); + (v1_rt::map_contains_key(&selected.local.clone(), "imported_fn".to_string()) + && !v1_rt::map_contains_key(&selected.local.clone(), "hidden_fn".to_string())) + } +} + +pub fn w_overlapping_selective_views_union_per_real_owner() -> bool { + { + let sig = fixture_sig(); + let empty_view = Rc::new(ResolvedFuncEnv { + name: "test.fixture.shared_owner".to_string(), + local: v1_rt::rc_empty_map::>(), + parents: Rc::new(vec![]), + }); + let admitted_view = Rc::new(ResolvedFuncEnv { + name: "test.fixture.shared_owner".to_string(), + local: v1_rt::rc_map_insert( + v1_rt::rc_empty_map::>(), + "imported_fn".to_string(), + sig.clone(), + ), + parents: Rc::new(vec![]), + }); + let merged = + merge_func_env_views_by_owner(Rc::new(vec![empty_view.clone(), admitted_view.clone()])); + (((merged.clone().len() as i64) == 1) + && v1_rt::map_contains_key( + &merged + .clone() + .first() + .cloned() + .clone() + .unwrap() + .local + .clone(), + "imported_fn".to_string(), + )) + } +} diff --git a/src/v1/tests/claim/resolved_call_emission_identity_internal_witness_test.dag b/src/v1/tests/claim/resolved_call_emission_identity_internal_witness_test.dag new file mode 100644 index 00000000000..759e2036cc7 --- /dev/null +++ b/src/v1/tests/claim/resolved_call_emission_identity_internal_witness_test.dag @@ -0,0 +1,69 @@ +module v1.tests.claim.resolved_call_emission_identity_internal_witness_test + +import v1.std.core { SourceDeclarationCall, error_type } +import std.induction { SubValueRelation } +import v1.compiler.infer { + resolved_call_target_from_declaration_lookup, + selective_func_env_view, + merge_func_env_views_by_owner +} +import v1.compiler.infer_sigs { ResolvedFuncSig, ResolvedFuncEnv } +import v1.compiler.infer_lookup { + ExactDeclarationIdentity, DeclarationNotIndexedAtQualifiedName, + AdmissionBearingDeclarationUnavailable +} + +// TEMPORARY PRODUCER WORKAROUND: SubValueRelation is not spelled in this module; +// it enters the emitted Rust only through ResolvedFuncSig's inferred type. Name +// its owning module directly (std.induction), rather than the v1.std.core +// re-export. Keep this import solely to force the mirror's use-line until #9063 +// derives realized names from inferred types; remove it when that repair lands. +data resolved_call_emission_identity_internal_witness_note: String = "DECLARED RUNG: white-box authoring-time evidence, measured 2026-08-24, for three compiler-internal call-identity decisions: AdmissionBearingDeclarationUnavailable retains its exact target identity, a selective parent view excludes unlisted locals, and overlapping selective views of one real owner union their admitted locals. These rows cannot be expressed through the required floor's dag plus src/v2 source-root envelope. They were split from test.claim.resolved_call_emission_identity_witness_test after required CI correctly refused its direct v1.compiler imports: dag/test is an executing home only for the eight black-box compile_dag_rust_emit_check controls retained there. This src/v1 file is parse-checked and all three rows passed when run directly during authoring, but no mechanism re-executes them: a regression in any of these three internal behaviours is SILENT. Direct execution proves only that the assertions held on the measurement date, never that CI keeps them true. None has an honest black-box discriminator today: global-bare fallback masks the two parent-view behaviours after their owned layer, while the unavailable-declaration state is not constructible from source. Re-homing these helpers into dag/std would invert the seed boundary by making compiler internals substrate API. NEXT-RUNG TRIGGER: a CI-visible harness that can reach v1.compiler internals without re-exporting them across the seed boundary, or a dag-reachable behavioural surface that can construct these exact internal states. dissolve-on: all three rows gain an enrolled behavioural home." + +fn w_unavailable_declaration_retains_exact_call_identity() -> Bool { + resolved_call_target_from_declaration_lookup( + declaration_lookup: AdmissionBearingDeclarationUnavailable { + identity: ExactDeclarationIdentity { owner_module_path: "test.fixture.owner", decl_name: "declared_call" }, + cause: DeclarationNotIndexedAtQualifiedName { qualified_name: "test.fixture.owner.declared_call" } + }, + func_name: "declared_call" + ) == SourceDeclarationCall { owner_module_path: "test.fixture.owner", decl_name: "declared_call" } +} + +fn fixture_sig() -> ResolvedFuncSig { + ResolvedFuncSig { + name: "fixture", + params: [], + inferred: error_type, + is_async: false, + output_provenance: [], + variant_provenance: empty_map() + } +} + +fn w_selective_function_import_refuses_unlisted_parent_local() -> Bool { + let sig = fixture_sig() + let parent = ResolvedFuncEnv { + name: "test.fixture.function_import_surface_provider", + local: map_insert(map_insert(empty_map(), "imported_fn", sig), "hidden_fn", sig), + parents: [] + } + let selected = selective_func_env_view(env: parent, names: ["imported_fn"]) + map_contains_key(selected.local, "imported_fn") && !map_contains_key(selected.local, "hidden_fn") +} + +fn w_overlapping_selective_views_union_per_real_owner() -> Bool { + let sig = fixture_sig() + let empty_view = ResolvedFuncEnv { + name: "test.fixture.shared_owner", + local: empty_map(), + parents: [] + } + let admitted_view = ResolvedFuncEnv { + name: "test.fixture.shared_owner", + local: map_insert(empty_map(), "imported_fn", sig), + parents: [] + } + let merged = merge_func_env_views_by_owner(views: [empty_view, admitted_view]) + merged |> count == 1 && map_contains_key((merged |> first).value.local, "imported_fn") +}