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
14 changes: 14 additions & 0 deletions src/v1/00_core.dag
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ type CompilerDiagnostic
| OwnershipViolation { binding: String, fn_name: String, consumers: Int, span: SourceSpan }
| VariantCollision { variant: String, enum1: String, enum2: String, span: SourceSpan }
| SoleConstructorViolation { type_name: String, span: SourceSpan }
| ConstructorReferenceAdmissionViolation { function_name: String, caller_module: String, owner_module_path: String, admitted: List<String>, span: SourceSpan }
| UnlistedImportUse { name: String, span: SourceSpan }
| AmbiguousReference { name: String, candidates: List<String>, span: SourceSpan }
| CallArgumentNameUnknown { callee: String, argument: String, declared: List<String>, span: SourceSpan }
Expand Down Expand Up @@ -288,6 +289,7 @@ fn diagnostic_to_span(d: CompilerDiagnostic) -> SourceSpan {
OwnershipViolation { binding: _, fn_name: _, consumers: _, span: s } => s
VariantCollision { variant: _, enum1: _, enum2: _, span: s } => s
SoleConstructorViolation { type_name: _, span: s } => s
ConstructorReferenceAdmissionViolation { function_name: _, caller_module: _, owner_module_path: _, admitted: _, span: s } => s
UnlistedImportUse { name: _, span: s } => s
AmbiguousReference { name: _, candidates: _, span: s } => s
CallArgumentNameUnknown { callee: _, argument: _, declared: _, span: s } => s
Expand Down Expand Up @@ -328,6 +330,8 @@ fn diagnostic_to_message(d: CompilerDiagnostic) -> String {
OwnershipViolation { binding: b, fn_name: f, consumers: c, span: _ } => concat("ownership: binding '", b, "' in '", f, "' has ", to_string(value: c), " consumers")
VariantCollision { variant: v, enum1: e1, enum2: e2, span: _ } => concat("variant '", v, "' appears in both '", e1, "' and '", e2, "'")
SoleConstructorViolation { type_name: t, span: _ } => concat("sole_constructor type '", t, "' cannot be constructed outside its defining module")
ConstructorReferenceAdmissionViolation { function_name: fname, caller_module: cm, owner_module_path: om, admitted: adm, span: _ } =>
concat("function '", fname, "' (declared in '", om, "') declares admit_callers and refuses this call from module '", cm, "' — admitted callers: [", join(adm, separator: ", "), "]")
UnlistedImportUse { name: n, span: _ } => concat("unlisted import use '", n, "' (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")
CallArgumentNameUnknown { callee: c, argument: a, declared: ds, span: _ } =>
Expand Down Expand Up @@ -931,6 +935,16 @@ fn field_init_node_value(n: Node) -> Node {
}
}

fn fn_admit_callers(n: Node) -> List<String>? {
match n.properties |> filter(p => p.name == "admit_callers") |> first {
Present { value: p } =>
Present { value: field_init_node_value(n: p).children
|> map(c => match expr_literal_string_optional(expr: c) { Present { value: v } => v Absent => "" })
|> filter(s => s != "") }
Absent => Absent
}
}

fn if_condition(texpr: Node) -> Node { expr_child_at(texpr: texpr, index: 0, role: "if condition") }
fn if_then_branch(texpr: Node) -> Node { expr_child_at(texpr: texpr, index: 1, role: "if then-branch") }
fn if_else_branch(texpr: Node) -> Node? { texpr.children |> skip(2) |> first }
Expand Down
19 changes: 18 additions & 1 deletion src/v1/02_parse.dag
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ type ArgResult { arg: Node, tokens: TokenStream, ctx: ParseContext, err: ErrorNo
type FieldResult { field: Node, tokens: TokenStream, ctx: ParseContext, err: ErrorNode? }
type FieldInitResult { field: Node, tokens: TokenStream, ctx: ParseContext, err: ErrorNode? }
type ResUseResult { resource_use: Node, tokens: TokenStream, ctx: ParseContext, err: ErrorNode? }
type AdmitCallersResult { props: List<Node>, tokens: TokenStream, ctx: ParseContext, err: ErrorNode? }

type ItemPrefixResult {
name: String
Expand Down Expand Up @@ -2448,6 +2449,17 @@ fn parse_fn_after_kw(tokens: TokenStream, ctx: ParseContext, start_span: SourceS
ItemResult { item: item, tokens: skip_newlines(tokens: r.tokens), ctx: r.ctx, err: none }
}

fn parse_optional_admit_callers(tokens: TokenStream, ctx: ParseContext) -> AdmitCallersResult {
let tokens = skip_newlines(tokens: tokens)
if tok_is_ident_text(tok: token_stream_first(stream: tokens), text: "admit_callers") {
let r = parse_field_init(tokens: tokens, ctx: ctx)
if has_err(err: r.err) { return AdmitCallersResult { props: [], tokens: r.tokens, ctx: r.ctx, err: r.err } }
AdmitCallersResult { props: [r.field], tokens: skip_newlines(tokens: r.tokens), ctx: r.ctx, err: none }
} else {
AdmitCallersResult { props: [], tokens: tokens, ctx: ctx, err: none }
}
}

fn parse_fn_body_from_prefix(prefix: ItemPrefixResult, start_span: SourceSpan) -> ItemResult {
let name = prefix.name
let name_span = prefix.name_span
Expand All @@ -2460,6 +2472,11 @@ fn parse_fn_body_from_prefix(prefix: ItemPrefixResult, start_span: SourceSpan) -
let named_dummy = Node { name: name, span: start_span, ident_span: Present { value: name_span }, children: [], params: all_params, inferred: none, return_cardinality: Required, uses: [], body: none, connective: NoConnective, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData }

let tokens = skip_newlines(tokens: prefix.tokens)
let admit_r = parse_optional_admit_callers(tokens: tokens, ctx: ctx)
if has_err(err: admit_r.err) { return ItemResult { item: named_dummy, tokens: admit_r.tokens, ctx: admit_r.ctx, err: admit_r.err } }
let admit_props = admit_r.props
let tokens = admit_r.tokens
let ctx = admit_r.ctx
let body_result = if tok_is_eq(tok: token_stream_first(stream: tokens)) {
let r = expect(tokens: tokens, expected: ExpectEq)
if has_err(err: r.err) { return ItemResult { item: named_dummy, tokens: r.tokens, ctx: ctx, err: r.err } }
Expand All @@ -2476,7 +2493,7 @@ fn parse_fn_body_from_prefix(prefix: ItemPrefixResult, start_span: SourceSpan) -
let item = Node { name: name, span: start_span, ident_span: Present { value: name_span }, children: [], params: all_params,
inferred: inferred, return_cardinality: Required, uses: [],
body: Present { value: body }, connective: NoConnective, transport: none,
properties: [], type_annotation: none,
properties: admit_props, type_annotation: none,
is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData }
ItemResult { item: item, tokens: skip_newlines(tokens: body_result.tokens), ctx: body_result.ctx, err: none }
}
Expand Down
15 changes: 13 additions & 2 deletions src/v1/04_infer.dag
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,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, UnresolvedType, FieldNotFound, MethodNotFound, MethodExistenceUndecided, MethodExistenceFrontierAdmitted, ReceiverTypeUnestablished, FrontierOccurrenceBudgetExceeded, MissingField, AmbiguousReference,
InternalError, TypeMismatch, VariantCollision, SoleConstructorViolation, ConstructorReferenceAdmissionViolation, UnresolvedType, FieldNotFound, MethodNotFound, MethodExistenceUndecided, MethodExistenceFrontierAdmitted, ReceiverTypeUnestablished, FrontierOccurrenceBudgetExceeded, MissingField, AmbiguousReference,
CallArgumentNameUnknown, CallPositionalSurplus,
resource_use_name_at, resource_use_resource,
is_child_accessor_in_model, is_tree_size_reducing, is_property_contraction,
Expand Down Expand Up @@ -140,7 +140,7 @@ import v1.compiler.infer_resolve {
import v1.compiler.infer_sigs {
ResolvedFuncSig, ResolvedFuncEnv, ResolveFuncSigsResult,
resolve_func_sigs, flatten_parent_envs,
FuncSigLookup, FuncSigResolved, FuncSigUnresolved, FuncSigAmbiguous
FuncSigLookup, FuncSigResolved, FuncSigUnresolved, FuncSigAmbiguous, FuncSigCallerNotAdmitted
}
import v1.compiler.infer_emit_info {
TypeRepr, StructRepr, EnumRepr,
Expand Down Expand Up @@ -606,6 +606,13 @@ fn ambiguous_reference_refusal(name: String, candidates: List<String>, span: Sou
}
}

fn constructor_reference_admission_refusal(function_name: String, owner_module_path: String, admitted: List<String>, span: SourceSpan, scope: InferScope) -> InferResult {
InferResult {
typed: semantic_expr_error_node(message: concat("function '", function_name, "' refuses this call — not in its admit_callers list"), span: span),
diagnostics: [make_error_node(diagnostic: ConstructorReferenceAdmissionViolation { function_name: function_name, caller_module: scope.module_name, owner_module_path: owner_module_path, admitted: admitted, span: span }, module_name: scope.module_name)]
}
}

fn type_mismatch_error(expected: String, got: String, span: SourceSpan, module_name: String) -> ErrorNode {
make_error_node(diagnostic: TypeMismatch { expected: expected, got: got, span: span }, module_name: module_name)
}
Expand Down Expand Up @@ -2483,6 +2490,8 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu
}
FuncSigAmbiguous { candidates: ambiguous_fn_candidates } =>
ambiguous_reference_refusal(name: name, candidates: ambiguous_fn_candidates, span: span, scope: scope)
FuncSigCallerNotAdmitted { function_name: adm_fname, owner_module_path: adm_owner, admitted: adm_admitted } =>
constructor_reference_admission_refusal(function_name: adm_fname, owner_module_path: adm_owner, admitted: adm_admitted, span: span, scope: scope)
FuncSigUnresolved =>
match lookup_binding_by_name(env: scope.type_env, name: name) {
Present { value: gbinding } =>
Expand Down Expand Up @@ -2657,6 +2666,8 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu
match call_sig_lookup {
FuncSigAmbiguous { candidates: ambiguous_fn_candidates } =>
ambiguous_reference_refusal(name: func_name, candidates: ambiguous_fn_candidates, span: span, scope: scope)
FuncSigCallerNotAdmitted { function_name: adm_fname, owner_module_path: adm_owner, admitted: adm_admitted } =>
constructor_reference_admission_refusal(function_name: adm_fname, owner_module_path: adm_owner, admitted: adm_admitted, span: span, scope: scope)
_ =>
let sig = func_sig_if_resolved(lookup: call_sig_lookup)
let sig_params = match sig {
Expand Down
61 changes: 39 additions & 22 deletions src/v1/04_lookup.dag
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import v1.compiler.infer_emit_info {

import v1.compiler.infer_sigs {
ResolvedFuncSig, ResolvedFuncEnv, lookup_resolved_sig,
FuncSigLookup, FuncSigResolved, FuncSigUnresolved, FuncSigAmbiguous
FuncSigLookup, FuncSigResolved, FuncSigUnresolved, FuncSigAmbiguous, FuncSigCallerNotAdmitted
}

import v1.compiler.infer_service {
Expand Down Expand Up @@ -81,11 +81,9 @@ fn lookup_func_sig(func_env: ResolvedFuncEnv, type_env: TypeEnv, name: String) -
match lookup_resolved_sig(env: func_env, name: name) {
FuncSigResolved { sig: sig } => FuncSigResolved { sig: sig }
FuncSigAmbiguous { candidates: cands } => FuncSigAmbiguous { candidates: cands }
FuncSigUnresolved =>
match func_sig_from_global_bare(type_env: type_env, name: name) {
Present { value: sig } => FuncSigResolved { sig: sig }
Absent => FuncSigUnresolved
}
FuncSigCallerNotAdmitted { function_name: fname, owner_module_path: om, admitted: adm } =>
FuncSigCallerNotAdmitted { function_name: fname, owner_module_path: om, admitted: adm }
FuncSigUnresolved => func_sig_from_global_bare(type_env: type_env, name: name)
}
}

Expand All @@ -94,6 +92,7 @@ fn func_sig_if_resolved(lookup: FuncSigLookup) -> ResolvedFuncSig? {
FuncSigResolved { sig: sig } => Present { value: sig }
FuncSigUnresolved => Absent
FuncSigAmbiguous { candidates: _ } => Absent
FuncSigCallerNotAdmitted { function_name: _, owner_module_path: _, admitted: _ } => Absent
}
}

Expand Down Expand Up @@ -126,12 +125,12 @@ fn borrowed_census_decl(type_env: TypeEnv, name: String) -> BorrowedCensusDecl?

data census_reserved_method_name_note: String = "Census precedence law (main-parity): the whole-pool census never serves an algebra method-template name (filter/any/contains/…) as a bare fn sig or tail callable. Those names belong to the known-method bridge in the ExprCall arm — a census sig for the UNLOADED v2.std.algebra typed filter(xs, f) as a plain call and the runtime died NoSuchFunction where main rewrote to the builtin method. Loaded providers are unaffected: lookup_resolved_sig runs before the census fallback."

fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> ResolvedFuncSig? {
fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> FuncSigLookup {
if algebra_method_template_name(name: name) {
return none
}
FuncSigUnresolved
} else {
match infer_builtin_call_type(name: name) {
Present { value: _ } => none
Present { value: _ } => FuncSigUnresolved
Absent =>
let borrowed = match lookup_binding_by_name_local(env: type_env, name: name) {
Present { value: binding } =>
Expand All @@ -142,7 +141,7 @@ fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> ResolvedFuncSig
Present { value: bd } =>
let node = bd.node
match (node.params |> count) > 0 || node.inferred != none || node.type_annotation != none {
false => Absent
false => FuncSigUnresolved
true =>
let excluded = borrowed_generic_param_names(params: node.params, source_indices: type_env.source_indices)
let raw_return = match node.inferred {
Expand All @@ -153,7 +152,7 @@ fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> ResolvedFuncSig
}
}
if bd.owner_module_path == type_env.module_path {
Present { value: ResolvedFuncSig {
FuncSigResolved { sig: ResolvedFuncSig {
name: name,
params: node.params,
inferred: raw_return,
Expand All @@ -162,18 +161,36 @@ fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> ResolvedFuncSig
variant_provenance: empty_map()
} }
} else {
let qualified_return = qualify_borrowed_type_names(n: raw_return, owner_module_path: bd.owner_module_path, env: type_env, excluded: excluded)
Present { value: ResolvedFuncSig {
name: name,
params: node.params,
inferred: qualified_return,
is_async: false,
output_provenance: [],
variant_provenance: empty_map()
} }
match fn_admit_callers(n: node) {
Present { value: admitted } =>
if admitted |> any(a => a == type_env.module_path) {
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 {
name: name,
params: node.params,
inferred: qualified_return,
is_async: false,
output_provenance: [],
variant_provenance: empty_map()
} }
} else {
FuncSigCallerNotAdmitted { function_name: name, owner_module_path: bd.owner_module_path, admitted: admitted }
}
Absent =>
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 {
name: name,
params: node.params,
inferred: qualified_return,
is_async: false,
output_provenance: [],
variant_provenance: empty_map()
} }
}
}
}
Absent => Absent
Absent => FuncSigUnresolved
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/v1/04_sigs.dag
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type FuncSigLookup
= FuncSigResolved { sig: ResolvedFuncSig }
| FuncSigUnresolved
| FuncSigAmbiguous { candidates: List<String> }
| FuncSigCallerNotAdmitted { function_name: String, owner_module_path: String, admitted: List<String> }

type ChainSigScan {
first_sig: ResolvedFuncSig?
Expand Down
Loading