Skip to content
Merged
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
14 changes: 11 additions & 3 deletions src/v2/compiler/03_name_resolve.dag
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module v2.compiler.name_resolve
import v2.std.language_model { LanguageModel }

import v2.compiler.normalize { NormalizedTree }
import v2.compiler.symbol_index_fill { symbol_index_fill_module_roots }
import v2.std.symbol_index { empty_symbol_index }
import v2.compiler.resolve {
DeclaredBinding,
Namespace,
Expand Down Expand Up @@ -470,7 +471,9 @@ fn admit_imports(
fn admission_namespace_base(lm: LanguageModel) -> Namespace {
Namespace {
bindings: empty_map(),
canonical_symbols: dag_language_model_canonical_symbols(lm: lm)
canonical_symbols: dag_language_model_canonical_symbols(lm: lm),
symbol_index: empty_symbol_index(),
module_qn: Empty
}
}

Expand Down Expand Up @@ -522,7 +525,12 @@ fn namespace_for_subject(
root: subject_module_root,
bindings: b
),
canonical_symbols: base.canonical_symbols
canonical_symbols: base.canonical_symbols,
symbol_index: symbol_index_fill_module_roots(
index: empty_symbol_index(),
roots: validated_roots
),
module_qn: admission.subject.name
},
subject_root: subject_module_root
},
Expand Down
135 changes: 58 additions & 77 deletions src/v2/compiler/03_resolve.dag
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ import v2.std.diagnostic {
diagnostics_singleton,
rejected_with_pending
}
import v2.std.qualified_name { QualifiedName }
import v2.std.symbol_index {
SymbolIndex,
empty_symbol_index,
symbol_index_lexical_lookup
}
import v2.std.node {
Arrow,
Atom,
Expand All @@ -57,7 +63,6 @@ import v2.std.node {
Transform,
TypeNode,
fold_node,
node_subtree_nodes,
node_with_occurrence_id,
well_formed
}
Expand All @@ -67,6 +72,8 @@ type ResolvedTree = Node
type Namespace {
bindings: Map<Symbol, Symbol>
canonical_symbols: Set<Symbol>
symbol_index: SymbolIndex
module_qn: QualifiedName
}

type Scope
Expand All @@ -90,7 +97,9 @@ fn empty_edge_list() -> List<Edge> {
fn empty_namespace() -> Namespace {
Namespace {
bindings: empty_map(),
canonical_symbols: empty_canonical_symbol_set()
canonical_symbols: empty_canonical_symbol_set(),
symbol_index: empty_symbol_index(),
module_qn: Empty
}
}

Expand Down Expand Up @@ -147,77 +156,19 @@ fn harvest_direct_atom_binding(root: Node, acc: Map<Symbol, Symbol>) -> Map<Symb
data resolve_variant_visibility_disposition: Disposition = Scaffold {
dissolves_to: SingleAuthority,
bind: DeclarationRef {
module_path: "v2.std.symbol_index",
decl_name: "symbol_index_lexical_lookup",
module_path: "v2.compiler.symbol_index_fill",
decl_name: "symbol_index_fill_unique_variant_aliases",
field: WholeDeclaration
}
}

fn harvest_variant_count_of(counts: Map<Symbol, Int>, sym: Symbol) -> Int {
match map_get(counts, sym) {
Accepted { value: opt, diagnostics: _ } => match opt {
Present { value: n } => n
Absent => 0
}
Rejected { diagnostics: _ } => 0
}
}

fn harvest_disj_variant_counts(root: Node) -> Map<Symbol, Int> {
fold(
node_subtree_nodes(root: root),
init: empty_map(),
f: fn(counts, n) {
match n.kind {
TypeNode { connective: Disj } =>
fold(n.children, init: counts, f: fn(c, e) {
match e.label {
Named { name: sym } =>
map_insert(m: c, key: sym, value: harvest_variant_count_of(counts: c, sym: sym) + 1)
Positional => c
}
})
_ => counts
}
}
)
}

fn harvest_unique_disj_variant_bindings(root: Node, acc: Map<Symbol, Symbol>) -> Map<Symbol, Symbol> {
let counts = harvest_disj_variant_counts(root: root)
fold(
node_subtree_nodes(root: root),
init: acc,
f: fn(a, n) {
match n.kind {
TypeNode { connective: Disj } =>
fold(n.children, init: a, f: fn(a2, e) {
match e.label {
Named { name: sym } =>
if harvest_variant_count_of(counts: counts, sym: sym) == 1 {
map_insert(m: a2, key: sym, value: sym)
} else {
a2
}
Positional => a2
}
})
_ => a
}
}
)
}

fn namespace_bindings_augment_from_module_atoms(
root: Node,
bindings: Map<Symbol, Symbol>
) -> Map<Symbol, Symbol> {
harvest_unique_disj_variant_bindings(
harvest_direct_atom_binding(
root: root,
acc: harvest_direct_atom_binding(
root: root,
acc: harvest_conj_named_bindings(root: root, acc: bindings)
)
acc: harvest_conj_named_bindings(root: root, acc: bindings)
)
}

Expand Down Expand Up @@ -266,7 +217,9 @@ fn build_program_namespace(tree: NormalizedTree, lm: LanguageModel) -> Namespace
root: tree,
acc: add_module_named_exports(root: tree, acc: empty_map())
),
canonical_symbols: dag_language_model_canonical_symbols(lm: lm)
canonical_symbols: dag_language_model_canonical_symbols(lm: lm),
symbol_index: empty_symbol_index(),
module_qn: Empty
}
}

Expand Down Expand Up @@ -342,6 +295,23 @@ fn canonical_atom(identity: Symbol, occurrence_id: NodeOccurrenceId) -> Node {
)
}

fn try_symbol_index_atom_identity(namespace: Namespace, name: Symbol) -> Optional<Symbol> {
match symbol_index_lexical_lookup(
index: namespace.symbol_index,
position: namespace.module_qn,
name: name
) {
Present { value: node } =>
match node.kind {
TypeNode { connective: Atom { identity: sym } } =>
optional_present(value: sym)
_ =>
optional_present(value: name)
}
Absent => optional_absent()
}
}

fn resolve_atom(n: Node, scope: Scope, identity: Symbol) -> Outcome<Node> {
match lookup_chain(s: scope, name: identity) {
Accepted { value: found, diagnostics: pending } => match found {
Expand All @@ -351,21 +321,32 @@ fn resolve_atom(n: Node, scope: Scope, identity: Symbol) -> Outcome<Node> {
diagnostics: pending
}
Absent =>
if namespace_has_canonical_symbol(
match try_symbol_index_atom_identity(
namespace: scope_root_module(s: scope),
name: identity
) {
Accepted {
value: canonical_atom(identity: identity, occurrence_id: n.occurrence_id),
diagnostics: pending
}
} else {
Rejected {
diagnostics: rejected_with_pending(
pending: pending,
rejected: diagnostics_singleton(d: unbound_symbol_diagnostic(n: n))
)
}
Present { value: canonical } =>
Accepted {
value: canonical_atom(identity: canonical, occurrence_id: n.occurrence_id),
diagnostics: pending
}
Absent =>
if namespace_has_canonical_symbol(
namespace: scope_root_module(s: scope),
name: identity
) {
Accepted {
value: canonical_atom(identity: identity, occurrence_id: n.occurrence_id),
diagnostics: pending
}
} else {
Rejected {
diagnostics: rejected_with_pending(
pending: pending,
rejected: diagnostics_singleton(d: unbound_symbol_diagnostic(n: n))
)
}
}
}
}
Rejected { diagnostics: ds } => Rejected { diagnostics: ds }
Expand Down
100 changes: 95 additions & 5 deletions src/v2/compiler/symbol_index_fill.dag
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,27 @@ import v2.extdeps.languages.dag {
qualified_name_from_module_node
}
import v2.std.algebra { fold_list }
import v2.std.collection {
Absent,
Map,
Present,
empty_map,
map_get,
map_insert
}
import v2.std.diagnostic { Accepted, Rejected }
import v2.std.node { Conj, Disj, Edge, Named, Node, Positional, Symbol, TypeNode }
import v2.std.logic { Int }
import v2.std.node {
Conj,
Disj,
Edge,
Named,
Node,
Positional,
Symbol,
TypeNode,
node_subtree_nodes
}
import v2.std.qualified_name { QualifiedName, qualified_name_snoc }
import v2.std.symbol_index { SymbolIndex, symbol_index_insert }

Expand Down Expand Up @@ -98,13 +117,84 @@ fn symbol_index_fill_containment_node(
}
}

fn disj_variant_count_of(counts: Map<Symbol, Int>, sym: Symbol) -> Int {
match map_get(counts, sym) {
Accepted { value: opt, diagnostics: _ } => match opt {
Present { value: n } => n
Absent => 0
}
Rejected { diagnostics: _ } => 0
}
}

fn disj_variant_counts_in_module(root: Node) -> Map<Symbol, Int> {
fold(
node_subtree_nodes(root: root),
init: empty_map(),
f: fn(counts, n) {
match n.kind {
TypeNode { connective: Disj } =>
fold(n.children, init: counts, f: fn(c, e) {
match e.label {
Named { name: sym } =>
map_insert(
m: c,
key: sym,
value: disj_variant_count_of(counts: c, sym: sym) + 1
)
Positional => c
}
})
_ => counts
}
}
)
}

fn symbol_index_fill_unique_variant_aliases(
index: SymbolIndex,
module_qn: QualifiedName,
root: Node
) -> SymbolIndex {
let counts = disj_variant_counts_in_module(root: root)
fold(
node_subtree_nodes(root: root),
init: index,
f: fn(acc, n) {
match n.kind {
TypeNode { connective: Disj } =>
fold(n.children, init: acc, f: fn(a2, e) {
match e.label {
Named { name: sym } =>
if disj_variant_count_of(counts: counts, sym: sym) == 1 {
symbol_index_insert(
index: a2,
qualified_path: qualified_name_snoc(qn: module_qn, segment: sym),
resolved: e.target
)
} else {
a2
}
Positional => a2
}
})
_ => acc
}
}
)
}

fn symbol_index_fill_module_root(index: SymbolIndex, root: Node) -> SymbolIndex {
match qualified_name_from_module_node(root: root) {
Accepted { value: module_qn, diagnostics: _ } =>
symbol_index_fill_containment_node(
index: index,
path: module_qn,
node: root
symbol_index_fill_unique_variant_aliases(
index: symbol_index_fill_containment_node(
index: index,
path: module_qn,
node: root
),
module_qn: module_qn,
root: root
)
Rejected { diagnostics: _ } => index
}
Expand Down
2 changes: 1 addition & 1 deletion src/v2/test/claim/resolve/variant_visibility_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fn variant_vis_accepts(src: String) -> Bool {
}
}

data variant_vis_doc: String = "src_unique_variants: bare match-arm variants Yes/No are each declared by exactly ONE type (module-unique) -> the interim variant-visibility resolver binds them and resolution ACCEPTS. src_ambiguous_variant: `Yes` is declared by TWO types (Classical, Mood) -> ambiguous -> the resolver REFUSES to bind it (fail-closed, no silent mis-bind), the bare `Yes` stays unbound, resolution REJECTS. The ambiguous case is the discriminating RED control: a flat bind-everything resolver (the wrong model) would bind `Yes` and wrongly accept."
data variant_vis_doc: String = "End-to-end wire proof: resolution ACCEPTS when SymbolIndex fill-time unique-variant aliases make bare match-arm variants resolvable (Classical-only Yes/No), REJECTS when aliases are withheld (Mood+Classical both declare Yes). SymbolIndex-path-alone equivalence is in symbol_index/containment_test.dag (symbol_index_variant_visibility_equivalence_holds + without_alias RED control)."

data src_unique_variants: String = "module variant_vis_pilot\n\ntype Classical = Yes | No\n\nfn flip(a: Classical) -> Classical { match a { Yes => No, No => Yes } }\n"

Expand Down
Loading