Files
vercel-labs--zerolang/native/zero-c/src/program_graph_memory_contracts.c
wehub-resource-sync e7738de6d2
CI / Deep Native Runtime Cases (1/6) (push) Has been skipped
CI / Native Preflight (push) Failing after 1s
CI / Native Runtime Cases (1/2) (push) Failing after 0s
CI / Native Runtime Cases (2/2) (push) Failing after 1s
CI / Native Metadata Reports (push) Failing after 0s
CI / Native Direct Backend Artifacts (push) Failing after 0s
CI / Native Sanitizer Smoke (push) Failing after 1s
CI / Command Contract Snapshots (push) Failing after 1s
CI / Deep Conformance Suite (push) Has been skipped
CI / Graph Build Perf (push) Failing after 1s
CI / Deep Native Preflight (push) Has been skipped
CI / Deep Native Runtime Cases (2/6) (push) Has been skipped
CI / Deep Native Runtime Cases (3/6) (push) Has been skipped
CI / Conformance Suite (push) Failing after 1s
CI / Workspace Checks (push) Failing after 0s
CI / Deep Native Runtime Cases (5/6) (push) Has been skipped
CI / Deep Native Runtime Cases (6/6) (push) Has been skipped
CI / Deep Native Runtime Cases (4/6) (push) Has been skipped
CI / Deep Graph Build Perf (push) Has been skipped
chore: import upstream snapshot with attribution
2026-07-13 12:29:30 +08:00

347 lines
18 KiB
C

#include "program_graph_contracts.h"
#include <stdio.h>
#include <string.h>
static bool memory_text_eq(const char *left, const char *right) { return strcmp(left ? left : "", right ? right : "") == 0; }
static bool memory_text_starts(const char *text, const char *prefix) { return text && prefix && strncmp(text, prefix, strlen(prefix)) == 0; }
static const ZProgramGraphNode *memory_node_by_id(const ZProgramGraph *graph, const char *id) {
for (size_t i = 0; graph && id && i < graph->node_len; i++) {
if (memory_text_eq(graph->nodes[i].id, id)) return &graph->nodes[i];
}
return NULL;
}
static const ZProgramGraphNode *memory_child(const ZProgramGraph *graph, const ZProgramGraphNode *node, const char *kind, size_t order) {
for (size_t i = 0; graph && node && kind && i < graph->edge_len; i++) {
const ZProgramGraphEdge *edge = &graph->edges[i];
if (edge->target == Z_PROGRAM_GRAPH_EDGE_TARGET_NODE && edge->order == order && memory_text_eq(edge->from, node->id) && memory_text_eq(edge->kind, kind)) {
return memory_node_by_id(graph, edge->to);
}
}
return NULL;
}
static const ZProgramGraphEdge *memory_owner_edge(const ZProgramGraph *graph, const char *node_id) {
for (size_t i = 0; graph && node_id && i < graph->edge_len; i++) {
const ZProgramGraphEdge *edge = &graph->edges[i];
if (edge->target == Z_PROGRAM_GRAPH_EDGE_TARGET_NODE && memory_text_eq(edge->to, node_id)) return edge;
}
return NULL;
}
static const ZProgramGraphResolutionReference *memory_ref_for_node(const ZProgramGraphResolutionFacts *resolution, const ZProgramGraphNode *node, const char *kind) {
for (size_t i = 0; resolution && node && i < resolution->reference_len; i++) {
const ZProgramGraphResolutionReference *ref = &resolution->references[i];
if ((!kind || memory_text_eq(ref->kind, kind)) && memory_text_eq(ref->node_id, node->id)) return ref;
}
return NULL;
}
static bool memory_maybe_binding(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const ZProgramGraphNode *subject) {
const ZProgramGraphResolutionReference *ref = memory_ref_for_node(resolution, subject, "identifier");
const ZProgramGraphNode *target = ref && ref->resolved ? memory_node_by_id(graph, ref->target_node) : NULL;
return target && memory_text_starts(target->type, "Maybe<");
}
static bool memory_subject_matches(const ZProgramGraphNode *subject, const char *name) { return subject && subject->kind == Z_PROGRAM_GRAPH_NODE_IDENTIFIER && memory_text_eq(subject->name, name); }
static bool memory_block_has_direct_return(const ZProgramGraph *graph, const ZProgramGraphNode *block) {
for (size_t i = 0; graph && block && i < graph->edge_len; i++) {
const ZProgramGraphEdge *edge = &graph->edges[i];
if (edge->target != Z_PROGRAM_GRAPH_EDGE_TARGET_NODE || !memory_text_eq(edge->from, block->id) || !memory_text_eq(edge->kind, "statement")) continue;
const ZProgramGraphNode *stmt = memory_node_by_id(graph, edge->to);
if (stmt && stmt->kind == Z_PROGRAM_GRAPH_NODE_RETURN) return true;
}
return false;
}
static bool memory_expr_is_false(const ZProgramGraphNode *expr) { return expr && expr->kind == Z_PROGRAM_GRAPH_NODE_LITERAL && memory_text_eq(expr->value, "false"); }
static bool memory_expr_is_has_access_for(const ZProgramGraph *graph, const ZProgramGraphNode *expr, const char *subject_name) {
return expr && expr->kind == Z_PROGRAM_GRAPH_NODE_FIELD_ACCESS && memory_text_eq(expr->name, "has") &&
memory_subject_matches(memory_child(graph, expr, "left", 0), subject_name);
}
static bool memory_expr_has_guard_for(const ZProgramGraph *graph, const ZProgramGraphNode *expr, const char *subject_name, size_t depth) {
if (!graph || !expr || !subject_name || depth > graph->node_len) return false;
if (memory_expr_is_has_access_for(graph, expr, subject_name)) return true;
for (size_t i = 0; i < graph->edge_len; i++) {
const ZProgramGraphEdge *edge = &graph->edges[i];
if (edge->target == Z_PROGRAM_GRAPH_EDGE_TARGET_NODE && memory_text_eq(edge->from, expr->id)) {
if (memory_expr_has_guard_for(graph, memory_node_by_id(graph, edge->to), subject_name, depth + 1)) return true;
}
}
return false;
}
static bool memory_block_has_then_guard(const ZProgramGraph *graph, const ZProgramGraphNode *block, const char *subject_name) {
const ZProgramGraphEdge *block_owner = block ? memory_owner_edge(graph, block->id) : NULL;
if (!block_owner || !memory_text_eq(block_owner->kind, "then")) return false;
const ZProgramGraphNode *if_node = memory_node_by_id(graph, block_owner->from);
if (!if_node || if_node->kind != Z_PROGRAM_GRAPH_NODE_IF) return false;
return memory_expr_has_guard_for(graph, memory_child(graph, if_node, "expr", 0), subject_name, 0);
}
static bool memory_expr_negative_has_guard_for(const ZProgramGraph *graph, const ZProgramGraphNode *expr, const char *subject_name) {
if (!expr || expr->kind != Z_PROGRAM_GRAPH_NODE_CALL) return false;
const ZProgramGraphNode *left = memory_child(graph, expr, "left", 0);
const ZProgramGraphNode *right = memory_child(graph, expr, "right", 1);
if (memory_text_eq(expr->name, "||")) {
return memory_expr_negative_has_guard_for(graph, left, subject_name) || memory_expr_negative_has_guard_for(graph, right, subject_name);
}
return memory_text_eq(expr->name, "==") &&
((memory_expr_is_has_access_for(graph, left, subject_name) && memory_expr_is_false(right)) ||
(memory_expr_is_false(left) && memory_expr_is_has_access_for(graph, right, subject_name)));
}
static bool memory_if_proves_subject_after(const ZProgramGraph *graph, const ZProgramGraphNode *stmt, const char *subject_name) {
if (!stmt || stmt->kind != Z_PROGRAM_GRAPH_NODE_IF) return false;
if (!memory_expr_negative_has_guard_for(graph, memory_child(graph, stmt, "expr", 0), subject_name)) return false;
return memory_block_has_direct_return(graph, memory_child(graph, stmt, "then", 0));
}
static bool memory_prior_negative_return_guarded_in_block(const ZProgramGraph *graph, const ZProgramGraphNode *block, size_t order, const char *subject_name) {
for (size_t i = 0; graph && block && i < graph->edge_len; i++) {
const ZProgramGraphEdge *edge = &graph->edges[i];
if (edge->target != Z_PROGRAM_GRAPH_EDGE_TARGET_NODE || edge->order >= order || !memory_text_eq(edge->from, block->id) || !memory_text_eq(edge->kind, "statement")) continue;
if (memory_if_proves_subject_after(graph, memory_node_by_id(graph, edge->to), subject_name)) return true;
}
return false;
}
static bool memory_prior_negative_return_guarded(const ZProgramGraph *graph, const ZProgramGraphNode *read, const char *subject_name) {
const char *current = read ? read->id : NULL;
for (size_t depth = 0; graph && current && depth < graph->node_len; depth++) {
const ZProgramGraphEdge *owner = memory_owner_edge(graph, current);
const ZProgramGraphNode *owner_node = owner ? memory_node_by_id(graph, owner->from) : NULL;
if (!owner_node) return false;
if (owner_node->kind == Z_PROGRAM_GRAPH_NODE_BLOCK && memory_text_eq(owner->kind, "statement") &&
memory_prior_negative_return_guarded_in_block(graph, owner_node, owner->order, subject_name)) return true;
current = owner_node->id;
}
return false;
}
static bool memory_short_circuit_guarded(const ZProgramGraph *graph, const ZProgramGraphNode *read, const char *subject_name) {
const char *current = read ? read->id : NULL;
for (size_t depth = 0; graph && current && depth < graph->node_len; depth++) {
const ZProgramGraphEdge *owner = memory_owner_edge(graph, current);
const ZProgramGraphNode *parent = owner ? memory_node_by_id(graph, owner->from) : NULL;
if (!parent) return false;
if (parent->kind == Z_PROGRAM_GRAPH_NODE_CALL && memory_text_eq(owner->kind, "right")) {
const ZProgramGraphNode *left = memory_child(graph, parent, "left", 0);
if (memory_text_eq(parent->name, "&&") && memory_expr_has_guard_for(graph, left, subject_name, 0)) return true;
if (memory_text_eq(parent->name, "||") && memory_expr_negative_has_guard_for(graph, left, subject_name)) return true;
}
current = parent->id;
}
return false;
}
static bool memory_value_read_guarded(const ZProgramGraph *graph, const ZProgramGraphNode *read, const char *subject_name) {
if (memory_short_circuit_guarded(graph, read, subject_name)) return true;
if (memory_prior_negative_return_guarded(graph, read, subject_name)) return true;
const char *current = read ? read->id : NULL;
for (size_t depth = 0; graph && current && depth < graph->node_len; depth++) {
const ZProgramGraphEdge *owner = memory_owner_edge(graph, current);
const ZProgramGraphNode *owner_node = owner ? memory_node_by_id(graph, owner->from) : NULL;
if (!owner_node) return false;
if (owner_node->kind == Z_PROGRAM_GRAPH_NODE_BLOCK && memory_block_has_then_guard(graph, owner_node, subject_name)) return true;
current = owner_node->id;
}
return false;
}
static bool fail_maybe_value_read(const ZProgramGraphNode *read, const ZProgramGraphNode *subject, const char *path, ZDiag *diag) {
if (diag) {
*diag = (ZDiag){0};
diag->code = 3051;
diag->path = read && read->path && read->path[0] ? read->path : path;
diag->line = read && read->line > 0 ? read->line : 1;
diag->column = read && read->column > 0 ? read->column : 1;
diag->length = 1;
snprintf(diag->message, sizeof(diag->message), "Maybe payload read requires a presence guard");
snprintf(diag->expected, sizeof(diag->expected), ".has proven true, check maybe_value, or rescue maybe_value err fallback");
snprintf(diag->actual, sizeof(diag->actual), "%s", subject && subject->name ? subject->name : "temporary Maybe value");
snprintf(diag->help, sizeof(diag->help), "guard the Maybe with `.has` before reading `.value`, or use `check`/`rescue` to handle absence");
}
return false;
}
static bool memory_node_contract_ok(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const ZProgramGraphNode *node, const char *path, ZDiag *diag) {
if (node->kind != Z_PROGRAM_GRAPH_NODE_FIELD_ACCESS || !memory_text_eq(node->name, "value")) return true;
const ZProgramGraphNode *subject = memory_child(graph, node, "left", 0);
if (!memory_maybe_binding(graph, resolution, subject)) return true;
if (!memory_value_read_guarded(graph, node, subject ? subject->name : "")) return fail_maybe_value_read(node, subject, path, diag);
return true;
}
bool z_program_graph_memory_contracts_ok(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const char *path, ZDiag *diag) {
for (size_t i = 0; graph && i < graph->node_len; i++) {
if (!memory_node_contract_ok(graph, resolution, &graph->nodes[i], path, diag)) return false;
}
return true;
}
size_t z_program_graph_memory_contract_violations(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const char *path, ZDiag *out, size_t cap) {
size_t found = 0;
for (size_t i = 0; graph && i < graph->node_len; i++) {
ZDiag diag = {0};
if (memory_node_contract_ok(graph, resolution, &graph->nodes[i], path, &diag)) continue;
if (out && found < cap) out[found] = diag;
found++;
}
return found;
}
static bool memory_integer_literal_value(const char *text, unsigned long long *out) {
if (!text || !text[0]) return false;
size_t body_len = strlen(text);
const char *last_underscore = strrchr(text, '_');
if (last_underscore && (last_underscore[1] == 'i' || last_underscore[1] == 'u')) body_len = (size_t)(last_underscore - text);
if (body_len == 0) return false;
unsigned long long value = 0;
bool saw_digit = false;
for (size_t index = 0; index < body_len; index++) {
char ch = text[index];
if (ch == '_') continue;
if (ch < '0' || ch > '9') return false;
value = value * 10ull + (unsigned long long)(ch - '0');
saw_digit = true;
}
if (!saw_digit) return false;
if (out) *out = value;
return true;
}
static bool memory_fixed_array_declared_len(const char *type_text, unsigned long long *out) {
if (!type_text || type_text[0] != '[') return false;
const char *close = strchr(type_text, ']');
if (!close || close == type_text + 1 || !close[1]) return false;
unsigned long long value = 0;
bool saw_digit = false;
for (const char *cursor = type_text + 1; cursor < close; cursor++) {
char ch = *cursor;
if (ch == '_') continue;
if (ch < '0' || ch > '9') return false;
value = value * 10ull + (unsigned long long)(ch - '0');
saw_digit = true;
}
if (!saw_digit) return false;
if (out) *out = value;
return true;
}
static size_t memory_edge_count(const ZProgramGraph *graph, const ZProgramGraphNode *node, const char *kind) {
size_t count = 0;
for (size_t i = 0; graph && node && kind && i < graph->edge_len; i++) {
const ZProgramGraphEdge *edge = &graph->edges[i];
if (edge->target == Z_PROGRAM_GRAPH_EDGE_TARGET_NODE && memory_text_eq(edge->from, node->id) && memory_text_eq(edge->kind, kind)) count++;
}
return count;
}
static const ZProgramGraphNode *memory_top_level_const(const ZProgramGraph *graph, const char *name) {
for (size_t i = 0; graph && name && name[0] && i < graph->node_len; i++) {
const ZProgramGraphNode *node = &graph->nodes[i];
if (node->kind == Z_PROGRAM_GRAPH_NODE_CONST && memory_text_eq(node->name, name)) return node;
}
return NULL;
}
static bool memory_repeat_count_value(const ZProgramGraph *graph, const ZProgramGraphNode *count_node, unsigned long long *out) {
if (!count_node) return false;
if (count_node->kind == Z_PROGRAM_GRAPH_NODE_LITERAL) return memory_integer_literal_value(count_node->value, out);
if (count_node->kind == Z_PROGRAM_GRAPH_NODE_IDENTIFIER) {
const ZProgramGraphNode *const_decl = memory_top_level_const(graph, count_node->name);
const ZProgramGraphNode *const_value = const_decl ? memory_child(graph, const_decl, "value", 0) : NULL;
if (const_value && const_value->kind == Z_PROGRAM_GRAPH_NODE_LITERAL) return memory_integer_literal_value(const_value->value, out);
}
return false;
}
static bool fail_fixed_array_length(const ZProgramGraphNode *literal, const char *declared_type, const char *actual_detail, const char *path, ZDiag *diag) {
if (diag) {
*diag = (ZDiag){0};
diag->code = 3006;
diag->path = literal && literal->path && literal->path[0] ? literal->path : path;
diag->line = literal && literal->line > 0 ? literal->line : 1;
diag->column = literal && literal->column > 0 ? literal->column : 1;
diag->length = 1;
snprintf(diag->message, sizeof(diag->message), "array literal length does not match expected fixed array");
snprintf(diag->expected, sizeof(diag->expected), "%s", declared_type ? declared_type : "fixed array type");
snprintf(diag->actual, sizeof(diag->actual), "%s", actual_detail ? actual_detail : "mismatched array literal length");
snprintf(diag->help, sizeof(diag->help), "make the lengths agree: resize the initializer or annotate the intended array length");
}
return false;
}
static bool memory_array_initializer_length_ok(const ZProgramGraph *graph, const char *declared_type, const ZProgramGraphNode *literal, const char *path, ZDiag *diag) {
unsigned long long declared_len = 0;
if (!literal || literal->kind != Z_PROGRAM_GRAPH_NODE_ARRAY_LITERAL) return true;
if (!memory_fixed_array_declared_len(declared_type, &declared_len)) return true;
if (memory_text_eq(literal->value, "repeat")) {
unsigned long long repeat_count = 0;
if (!memory_repeat_count_value(graph, memory_child(graph, literal, "arg", 1), &repeat_count)) return true;
if (repeat_count == declared_len) return true;
char actual_detail[96];
snprintf(actual_detail, sizeof(actual_detail), "repeat count %llu", repeat_count);
return fail_fixed_array_length(literal, declared_type, actual_detail, path, diag);
}
size_t element_count = memory_edge_count(graph, literal, "arg");
if ((unsigned long long)element_count == declared_len) return true;
char actual_detail[96];
snprintf(actual_detail, sizeof(actual_detail), "%zu element(s)", element_count);
return fail_fixed_array_length(literal, declared_type, actual_detail, path, diag);
}
static const char *memory_assignment_target_array_type(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const ZProgramGraphNode *assignment) {
const ZProgramGraphNode *target = memory_child(graph, assignment, "target", 0);
if (!target || target->kind != Z_PROGRAM_GRAPH_NODE_IDENTIFIER) return NULL;
const ZProgramGraphResolutionReference *ref = memory_ref_for_node(resolution, target, "identifier");
const ZProgramGraphNode *binding = ref && ref->resolved ? memory_node_by_id(graph, ref->target_node) : NULL;
if (!binding || binding->kind != Z_PROGRAM_GRAPH_NODE_LET) return NULL;
return binding->type;
}
static bool memory_fixed_array_node_ok(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const ZProgramGraphNode *node, const char *path, ZDiag *diag) {
const char *declared_type = NULL;
const char *init_edge = NULL;
if (node->kind == Z_PROGRAM_GRAPH_NODE_LET) {
declared_type = node->type;
init_edge = "expr";
} else if (node->kind == Z_PROGRAM_GRAPH_NODE_CONST) {
declared_type = node->type;
init_edge = "value";
} else if (node->kind == Z_PROGRAM_GRAPH_NODE_ASSIGNMENT) {
declared_type = memory_assignment_target_array_type(graph, resolution, node);
init_edge = "expr";
} else {
return true;
}
if (!declared_type || declared_type[0] != '[') return true;
const ZProgramGraphNode *init = memory_child(graph, node, init_edge, 0);
return memory_array_initializer_length_ok(graph, declared_type, init, path, diag);
}
bool z_program_graph_fixed_array_length_contracts_ok(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const char *path, ZDiag *diag) {
for (size_t i = 0; graph && i < graph->node_len; i++) {
if (!memory_fixed_array_node_ok(graph, resolution, &graph->nodes[i], path, diag)) return false;
}
return true;
}
size_t z_program_graph_fixed_array_length_contract_violations(const ZProgramGraph *graph, const ZProgramGraphResolutionFacts *resolution, const char *path, ZDiag *out, size_t cap) {
size_t found = 0;
for (size_t i = 0; graph && i < graph->node_len; i++) {
ZDiag diag = {0};
if (memory_fixed_array_node_ok(graph, resolution, &graph->nodes[i], path, &diag)) continue;
if (out && found < cap) out[found] = diag;
found++;
}
return found;
}