Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
11 changes: 11 additions & 0 deletions dag/std/decl_ref.dag
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ type DeclarationRef {
field: DeclField
}

// WHETHER A REFERENCE NAMES A TYPE PARAMETER, read from the carrier and never from a spelling. It
// lives beside the type for the reason the constructors do: one authority for what the field arm
// means (DESIGN section 3).
fn declaration_ref_is_type_parameter(ref: DeclarationRef) -> Bool {
match ref.field {
TypeParameter { name: _ } => true
WholeDeclaration => false
NamedField { field_name: _ } => false
}
}

// The constructors live HERE, beside the type they construct — single authority (DESIGN section 3).
// Two parallel lanes each minted an identical fn decl_ref/decl_field_ref pair
// (std.primitive_identity and std.roster_frontier, both 2026-08-01), and because v1-seed fn names
Expand Down
4 changes: 4 additions & 0 deletions fixtures/generic_identity_census/a.dag
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,7 @@ fn boxed() -> Box<Int> {
fn unbox<Q>(b: Box<Q>) -> Q {
b.item
}

fn same_spelling_as_a_record_parameter<Q>(b: Box<Q>, q: Q) -> Q {
q
}
2 changes: 1 addition & 1 deletion src/v1/04_infer.dag
Original file line number Diff line number Diff line change
Expand Up @@ -13617,7 +13617,7 @@ fn unify_generics(formal: Node, actual: Node, generic_names: List<String>, sourc
match formal.children |> first {
Present { value: fc } =>
match actual.children |> first {
Present { value: ac } => unify_generics(formal: fc, actual: ac, generic_names: generic_names, source_indices: source_indices, acc: acc)
Present { value: ac } => unify_generics(formal: fc, actual: child_type_node(ch: ac), generic_names: generic_names, source_indices: source_indices, acc: acc)
Absent => acc
}
Absent => acc
Expand Down
22 changes: 21 additions & 1 deletion src/v1/04_resolve.dag
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module v1.compiler.infer_resolve

import std.decl_ref { DeclarationRef, decl_ref, decl_type_parameter_ref }
import std.decl_ref { DeclarationRef, decl_ref, decl_type_parameter_ref, declaration_ref_is_type_parameter }
import std.occurrence_identity { OccurrenceSynthetic }

import std.types { SourceSpan, container_param_name }
Expand Down Expand Up @@ -295,7 +295,27 @@ fn preserve_nominal_brand_on_resolve(
} else { preserve_outer_optional_cardinality(outer: identity, inner: structural) }
}

// A TYPE-PARAMETER REFERENCE IS NOT A NOMINAL ALIAS, AND IT IS KNOWN BY ITS MARK, NOT ITS SPELLING
// (docs/plans/derived-node-identity-design.md, copy law L1; class gunbc.recurring_failure_mode
// generic_identity_decided_by_spelling). binder_marked_type records (owner, TypeParameter) on every
// reference to an item's own parameter. This function then looked the node up BY NAME and returned
// whatever the environment bound to that spelling, so a parameter spelled like some other binding in
// scope was replaced by that binding and its own identity was dropped: measured by
// //gunbc/instruments:generic-identity-census as formal_declaration_bound_conformance leaves carrying
// neither mark, where the signature they were read from carried both. There is nothing to peel
// beneath a parameter, so a node carrying the mark is returned as it was given.
fn node_is_type_parameter_reference(n: Node) -> Bool {
match n.declaration {
Present { value: ref } => declaration_ref_is_type_parameter(ref: ref)
Absent => false
}
}

fn peel_nominal_alias_identity(n: Node, env: TypeEnv, module_name: String) -> Node {
if node_is_type_parameter_reference(n: n) { n } else { peel_nominal_alias_identity_by_name(n: n, env: env, module_name: module_name) }
}

fn peel_nominal_alias_identity_by_name(n: Node, env: TypeEnv, module_name: String) -> Node {
let source_indices = env.source_indices
let brand = authored_name_at(source_indices: source_indices, node: n)
match lookup_type_for(env: env, node: n) {
Expand Down
8 changes: 8 additions & 0 deletions src/v1/stage0/src/std_decl_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ pub struct DeclarationRef {
pub field: Rc<DeclField>,
}

pub fn declaration_ref_is_type_parameter(ref_: Rc<DeclarationRef>) -> bool {
match (*ref_.field.clone()).clone() {
DeclField::TypeParameter { name: _, .. } => true,
DeclField::WholeDeclaration => false,
DeclField::NamedField { field_name: _, .. } => false,
}
}

#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
Expand Down
23 changes: 22 additions & 1 deletion src/v1/stage0/src/v1_compiler_infer_resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use self::AliasKind::*;
use self::KindInhabitance::*;
pub use crate::std_decl_ref::DeclarationRef;
pub use crate::std_decl_ref::{decl_ref, decl_type_parameter_ref};
pub use crate::std_decl_ref::{
decl_ref, decl_type_parameter_ref, declaration_ref_is_type_parameter,
};
pub use crate::std_induction::SubValueRelation;
use crate::std_induction::SubValueRelation::SubValueUnknown;
pub use crate::std_occurrence_identity::NodeOccurrenceIdentity;
Expand Down Expand Up @@ -413,7 +415,26 @@ pub fn preserve_nominal_brand_on_resolve(
}
}

pub fn node_is_type_parameter_reference(n: Rc<Node>) -> bool {
match n.declaration.clone() {
Some(ref_) => crate::std_decl_ref::declaration_ref_is_type_parameter(ref_.clone()),
std::option::Option::None => false,
}
}

pub fn peel_nominal_alias_identity(n: Rc<Node>, env: Rc<TypeEnv>, module_name: String) -> Rc<Node> {
if node_is_type_parameter_reference(n.clone()) {
n.clone()
} else {
peel_nominal_alias_identity_by_name(n.clone(), env.clone(), module_name.clone())
}
}

pub fn peel_nominal_alias_identity_by_name(
n: Rc<Node>,
env: Rc<TypeEnv>,
module_name: String,
) -> Rc<Node> {
{
let source_indices = env.source_indices.clone();
let brand = crate::v1_std_core::authored_name_at(source_indices.clone(), n.clone());
Expand Down
Loading