Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/v1/00_core.dag
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ type TextFile {
content: String
}

// UnlistedVariantValueUse EXISTS SEPARATELY FROM UnlistedImportUse ON PURPOSE. The situation is the
// same one UnlistedImportUse reports for a TYPE -- a name used without an import -- and reusing that
// constructor for the bare nullary VARIANT case was tried and withdrawn: v1.compiler.emit_rust
// group_unlisted_type_names folds every diagnostic in typed.diagnostics selecting UnlistedImportUse by
// constructor alone, and hands the result to reference_derived_use_lines, which SYNTHESIZES use-lines
// from it. That selector is total over the diagnostic type and blind to the stage that minted it -- an
// ErrorNode carries a module name and a diagnostic and nothing that says which stage produced it -- so
// any stage emitting UnlistedImportUse is silently wired into production emission, which no author
// would see from the code they were editing. A distinct constructor is therefore not a naming
// preference: it is what makes the standing prohibition on adding bare variants to synthesis output
// hold BY CONSTRUCTION rather than by a byte-diff that can only report 'not on this subject today'.
type CompilerDiagnostic
= UnresolvedImport { module_path: String, importing_module: String, span: SourceSpan }
| MissingExport { name: String, module_path: String, importing_module: String, span: SourceSpan }
Expand Down Expand Up @@ -199,6 +210,7 @@ type CompilerDiagnostic
| DeclaredTypeNotInhabited { position: String, expected: String, got: String, span: SourceSpan }
| DeclaredTypeInhabitanceUndecided { position: String, reason: String, span: SourceSpan }
| UnlistedImportUse { name: String, span: SourceSpan }
| UnlistedVariantValueUse { name: String, span: SourceSpan }
| AmbiguousReference { name: String, candidates: List<String>, span: SourceSpan }
| DataReferenceVisibilityBudgetExceeded { name: String, span: SourceSpan }
| ParameterDefaultFormNotAdmitted { parameter: String, admitted: List<String>, span: SourceSpan }
Expand Down Expand Up @@ -350,6 +362,7 @@ fn diagnostic_to_span(d: CompilerDiagnostic) -> SourceSpan {
DeclaredTypeNotInhabited { position: _, expected: _, got: _, span: s } => s
DeclaredTypeInhabitanceUndecided { position: _, reason: _, span: s } => s
UnlistedImportUse { name: _, span: s } => s
UnlistedVariantValueUse { name: _, span: s } => s
AmbiguousReference { name: _, candidates: _, span: s } => s
DataReferenceVisibilityBudgetExceeded { name: _, span: s } => s
ParameterDefaultFormNotAdmitted { parameter: _, admitted: _, span: s } => s
Expand Down Expand Up @@ -432,6 +445,7 @@ fn diagnostic_to_message(d: CompilerDiagnostic) -> String {
DeclaredTypeInhabitanceUndecided { position: pos, reason: r, span: _ } =>
concat("declared-type inhabitance is undecidable at the ", pos, " (", r, "): the modeled facts do not settle whether the produced value inhabits its declared type, so no verdict is asserted in either direction")
UnlistedImportUse { name: n, span: _ } => concat("unlisted import use '", n, "' (referenced but not in any import's name list)")
UnlistedVariantValueUse { name: n, span: _ } => concat("unlisted variant value use '", n, "' (a coproduct arm referenced but not in any import's name list)")
AmbiguousReference { name: n, candidates: cs, span: _ } => concat("ambiguous reference '", n, "': ", to_string(value: cs |> count), " candidates: ", join(cs, separator: ", "), " — qualify by containment path, alias, or rename")
DataReferenceVisibilityBudgetExceeded { name: n, span: _ } =>
concat("visible declarations of '", n, "' could not be enumerated: the import re-export walk exceeded its depth bound, so no verdict is asserted about how many declarations answer to the name")
Expand Down Expand Up @@ -490,6 +504,7 @@ data diagnostic_frontier_occurrence_key_note: String = "The canonical accessor f
fn is_error_diagnostic(d: CompilerDiagnostic) -> Bool {
match d {
UnlistedImportUse { name: _, span: _ } => false
UnlistedVariantValueUse { name: _, span: _ } => false
MethodExistenceFrontierAdmitted { method: _, receiver_type: _, trigger: _, span: _ } => false
ReceiverTypeUnestablished { method: _, span: _ } => false
WhereRefinementUnenforced { predicate: _, formal_type: _, reason: r, span: _ } =>
Expand All @@ -506,6 +521,7 @@ fn is_interpreter_blocking_diagnostic(d: CompilerDiagnostic) -> Bool {
WhereRefinementUnenforced { predicate: _, formal_type: _, reason: r, span: _ } =>
!is_where_refinement_unenforced_advisory_reason(reason: r)
UnlistedImportUse { name: _, span: _ } => false
UnlistedVariantValueUse { name: _, span: _ } => false
MethodExistenceFrontierAdmitted { method: _, receiver_type: _, trigger: _, span: _ } => false
ReceiverTypeUnestablished { method: _, span: _ } => false
ServiceConfigReferenceJudgmentDeferred { field: _, referenced_name: _, trigger: _, span: _ } => false
Expand All @@ -517,6 +533,7 @@ fn is_interpreter_blocking_diagnostic(d: CompilerDiagnostic) -> Bool {
fn is_discovery_corpus_advisory_typecheck_diagnostic(d: CompilerDiagnostic) -> Bool {
match d {
UnlistedImportUse { name: _, span: _ } => true
UnlistedVariantValueUse { name: _, span: _ } => true
MethodExistenceFrontierAdmitted { method: _, receiver_type: _, trigger: _, span: _ } => true
ReceiverTypeUnestablished { method: _, span: _ } => true
ServiceConfigReferenceJudgmentDeferred { field: _, referenced_name: _, trigger: _, span: _ } => true
Expand Down
102 changes: 77 additions & 25 deletions src/v1/04_infer.dag
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import v1.std.core {
Cardinality, Required, CardOptional,
ErrorNode, make_error_node, is_error_diagnostic, diagnostic_to_span,
FrontierOccurrenceKey, diagnostic_frontier_occurrence_key,
InternalError, TypeMismatch, VariantCollision, SoleConstructorViolation, OptionalCastNotEliminated, BareNoneNotAdmittedByFieldType, ConstructorCallAdmissionRefused, UnresolvedType, FieldNotFound, MethodNotFound, MethodExistenceUndecided, MethodExistenceFrontierAdmitted, ReceiverTypeUnestablished, FrontierOccurrenceBudgetExceeded, MissingField, AmbiguousReference, ServiceConfigReferenceJudgmentDeferred,
InternalError, TypeMismatch, VariantCollision, SoleConstructorViolation, OptionalCastNotEliminated, BareNoneNotAdmittedByFieldType, ConstructorCallAdmissionRefused, UnresolvedType, FieldNotFound, MethodNotFound, MethodExistenceUndecided, MethodExistenceFrontierAdmitted, ReceiverTypeUnestablished, FrontierOccurrenceBudgetExceeded, MissingField, AmbiguousReference, ServiceConfigReferenceJudgmentDeferred, UnlistedVariantValueUse,
CallArgumentNameUnknown, CallPositionalSurplus, CallPositionalDeficit, CallNamedArgOnFunctionValue, CallArgumentDuplicate,
resource_use_name_at, resource_use_resource,
is_child_accessor_in_model, is_tree_size_reducing, is_property_contraction,
Expand Down Expand Up @@ -660,6 +660,49 @@ fn variant_owner_node(scope: InferScope, name: String) -> Node? {
}
}

// THE BARE NULLARY VARIANT REFERENCE'S OWN UNLISTED-USE OBSERVATION, ON ITS OWN CONSTRUCTOR, and why
// it is emitted here
// rather than left to the type path. `resolve_node_bounded`'s masked-leaf check reports
// UnlistedImportUse for a TYPE named without an import; the identical situation one channel over --
// a coproduct ARM named without an import -- reported nothing at all, because the arm binds through
// the constructor channel (`merge_global_bare_variant_locals` merges a whole-closure base under the
// checked own+direct-imports fold) and never reaches that leaf. Measured on a discriminating pair in
// `gunbc.constructor_binding_channel`: same fixture, same absent import, advisory for the type
// reference and silence for the arm.
//
// WHY THAT SILENCE IS NOT COSMETIC. `v1.compiler.emit_rust` `collect_value_ref_names` harvests
// ExprCall unconditionally and ExprRecordLit through `record_lit_ref_names`, so the payload-carrying
// constructor forms already reach the reference-derived use-line producer. ExprVar carrying a
// VariantValueBinding falls to that function's `_ => []`, so the BARE NULLARY arm -- Absent, Empty,
// NoConnective, the unit arm of nearly every coproduct here -- contributes nothing, and a census of
// the use-line repair population built on the existing instrument cannot be complete while it does.
// This adds the missing observation; it does not change what binds or what refuses.
//
// AND IT DOES NOT REACH THE EMITTER, BY CONSTRUCTION RATHER THAN BY MEASUREMENT. The first cut of this
// observation reused `UnlistedImportUse`, which `v1.compiler.emit_rust` `group_unlisted_type_names`
// folds out of `typed.diagnostics` -- a set that carries `infer_diags` -- into the input
// `reference_derived_use_lines` synthesizes use-lines from. That would have added bare variants to
// production synthesis output, which a standing hold forbids until the pre-cut population is counted.
// `UnlistedVariantValueUse` is a separate constructor that selector cannot match, so byte-identical
// emission is a property of the shape rather than a diff someone has to keep re-running. The reason
// the constructor exists is recorded on the constructor, in v1.std.core.
//
// THE OWNER-FILE TEST IS WHAT KEEPS IT FROM FIRING ON LOCAL DECLARATIONS. `source_visible_names`
// carries imports and the kernel surface, never the module's own declarations, so membership alone
// would report every locally-declared arm. The owner node's file is compared with the reference's,
// which is the same identity test `insert_variant_owner_checked` already uses for same-owner.
fn unlisted_variant_use_diagnostics(scope: InferScope, name: String, span: SourceSpan, owner: Node?) -> List<ErrorNode> {
match owner {
Present { value: owner_node } =>
if owner_node.span.file != span.file
&& map_is_empty(m: scope.type_env.source_visible_names) == false
&& map_has(m: scope.type_env.source_visible_names, key: name) == false {
[make_error_node(diagnostic: UnlistedVariantValueUse { name: name, span: span }, module_name: scope.module_name)]
} else { [] }
Absent => []
}
}

fn infer_var_binding_kind(scope: InferScope, name: String) -> VarBindingKind {
match lookup_variant_parent_enum(scope: scope, name: name) {
Present { value: parent_enum } => VariantValueBinding { parent_enum: parent_enum }
Expand Down Expand Up @@ -4263,14 +4306,17 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu
let scope_parent = lookup_variant_parent_enum(scope: scope, name: name)
match scope_parent {
Present { value: scope_enum } =>
ok_infer(texpr: make_named_expr_node(
name: name,
expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum } } },
children: [],
inferred: Present { value: Resolved { node: variant_reference_inferred_node(expected: expected, name: name, owner_name: scope_enum, scope: scope, fallback: binding.resolved) } },
span: span,
name_span: span
))
InferResult {
typed: make_named_expr_node(
name: name,
expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum } } },
children: [],
inferred: Present { value: Resolved { node: variant_reference_inferred_node(expected: expected, name: name, owner_name: scope_enum, scope: scope, fallback: binding.resolved) } },
span: span,
name_span: span
),
diagnostics: unlisted_variant_use_diagnostics(scope: scope, name: name, span: span, owner: variant_owner_node(scope: scope, name: name))
}
Absent =>
let binding_kind = infer_var_binding_kind(scope: scope, name: name)
ok_infer(texpr: make_named_expr_node(
Expand Down Expand Up @@ -4313,14 +4359,17 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu
let scope_parent = lookup_variant_parent_enum(scope: scope, name: name)
match scope_parent {
Present { value: scope_enum } =>
ok_infer(texpr: make_named_expr_node(
name: name,
expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum } } },
children: [],
inferred: Present { value: Resolved { node: variant_reference_inferred_node(expected: expected, name: name, owner_name: scope_enum, scope: scope, fallback: gbinding.resolved) } },
span: span,
name_span: span
))
InferResult {
typed: make_named_expr_node(
name: name,
expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum } } },
children: [],
inferred: Present { value: Resolved { node: variant_reference_inferred_node(expected: expected, name: name, owner_name: scope_enum, scope: scope, fallback: gbinding.resolved) } },
span: span,
name_span: span
),
diagnostics: unlisted_variant_use_diagnostics(scope: scope, name: name, span: span, owner: variant_owner_node(scope: scope, name: name))
}
Absent =>
let binding_kind = infer_var_binding_kind(scope: scope, name: name)
ok_infer(texpr: make_named_expr_node(
Expand All @@ -4336,14 +4385,17 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu
let expected_variant_enum = expected_variant_owner_instantiation(expected: expected, name: name, scope: scope)
match expected_variant_enum {
Present { value: exp_enum } =>
ok_infer(texpr: make_named_expr_node(
name: name,
expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: authored_name_at(source_indices: scope.type_env.source_indices, node: exp_enum) } } },
children: [],
inferred: Present { value: Resolved { node: exp_enum } },
span: span,
name_span: span
))
InferResult {
typed: make_named_expr_node(
name: name,
expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: authored_name_at(source_indices: scope.type_env.source_indices, node: exp_enum) } } },
children: [],
inferred: Present { value: Resolved { node: exp_enum } },
span: span,
name_span: span
),
diagnostics: unlisted_variant_use_diagnostics(scope: scope, name: name, span: span, owner: Present { value: exp_enum })
}
Absent =>
let var_ambiguity_cands = global_bare_strict_ambiguity_candidates(env: scope.type_env, name: name)
if (var_ambiguity_cands |> count) > 0 {
Expand Down
3 changes: 3 additions & 0 deletions src/v1/stage0/src/cli_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3746,6 +3746,7 @@ pub fn compile_clean_diagnostic_is_advisory(d: &Rc<ErrorNode>) -> bool {
&& matches!(
d.diagnostic.as_ref(),
crate::v1_std_core::CompilerDiagnostic::UnlistedImportUse { .. }
| crate::v1_std_core::CompilerDiagnostic::UnlistedVariantValueUse { .. }
| crate::v1_std_core::CompilerDiagnostic::ComplexityUnknown { .. }
| crate::v1_std_core::CompilerDiagnostic::WhereRefinementUnenforced { .. }
// A non-blocking variant that is absent from this list is counted by
Expand Down Expand Up @@ -5416,6 +5417,7 @@ pub fn compile_clean_diagnostic_histogram_key(d: &Rc<ErrorNode>) -> (String, Str
CompilerDiagnostic::ServiceConfigReferenceJudgmentDeferred { .. } => {
"ServiceConfigReferenceJudgmentDeferred"
}
CompilerDiagnostic::UnlistedVariantValueUse { .. } => "UnlistedVariantValueUse",
};
let name = match d.diagnostic.as_ref() {
CompilerDiagnostic::UnresolvedImport { module_path, .. } => module_path.clone(),
Expand Down Expand Up @@ -5458,6 +5460,7 @@ pub fn compile_clean_diagnostic_histogram_key(d: &Rc<ErrorNode>) -> (String, Str
CompilerDiagnostic::DeclaredTypeNotInhabited { position, .. } => position.clone(),
CompilerDiagnostic::DeclaredTypeInhabitanceUndecided { position, .. } => position.clone(),
CompilerDiagnostic::UnlistedImportUse { name, .. } => name.clone(),
CompilerDiagnostic::UnlistedVariantValueUse { name, .. } => name.clone(),
CompilerDiagnostic::AmbiguousReference { name, .. } => name.clone(),
CompilerDiagnostic::DataReferenceVisibilityBudgetExceeded { name, .. } => name.clone(),
CompilerDiagnostic::ParameterDefaultFormNotAdmitted { parameter, .. } => parameter.clone(),
Expand Down
1 change: 1 addition & 0 deletions src/v1/stage0/src/emitted_population.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
// src/v1_rt.rs
// src/v1_std_core.rs
// src/v1_test_non_ascii_perf_fixture.rs
// src/v1_tests_claim_bare_variant_reference_occurrence_control_test.rs
// src/v1_tests_claim_checkpoint_identity_keying_witness_test.rs
// src/v1_tests_claim_transport_roster_closure_witness_test.rs
// src/wt_a.rs
Expand Down
1 change: 1 addition & 0 deletions src/v1/stage0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub mod v1_probe_emit_interp;
pub mod v1_rt;
pub mod v1_std_core;
pub mod v1_test_non_ascii_perf_fixture;
pub mod v1_tests_claim_bare_variant_reference_occurrence_control_test;
pub mod v1_tests_claim_checkpoint_identity_keying_witness_test;
pub mod v1_tests_claim_transport_roster_closure_witness_test;
pub mod wt_a;
Expand Down
Loading
Loading