| 3912 | const char **source_name); |
| 3913 | |
| 3914 | void rust_process_statement(RustLSPContext *ctx, TSNode node) { |
| 3915 | if (ts_node_is_null(node)) |
| 3916 | return; |
| 3917 | const char *kind = ts_node_type(node); |
| 3918 | |
| 3919 | /* let_declaration: let pat: T = expr; |
| 3920 | * |
| 3921 | * Bidirectional inference: if the user wrote `let v: Vec<String> = …;` |
| 3922 | * we pass `Vec<String>` as the expected hint when synthesising the |
| 3923 | * RHS. That lets ambiguous calls like `Vec::new()` keep their full |
| 3924 | * template arguments through the chain. */ |
| 3925 | if (strcmp(kind, "let_declaration") == 0) { |
| 3926 | TSNode pat = ts_node_child_by_field_name(node, "pattern", 7); |
| 3927 | TSNode tn = ts_node_child_by_field_name(node, "type", 4); |
| 3928 | TSNode val = ts_node_child_by_field_name(node, "value", 5); |
| 3929 | |
| 3930 | const CBMType *annotated = NULL; |
| 3931 | if (!ts_node_is_null(tn)) { |
| 3932 | annotated = rust_parse_type_node(ctx, tn); |
| 3933 | } |
| 3934 | const CBMType *let_type = annotated; |
| 3935 | if ((!let_type || cbm_type_is_unknown(let_type)) && !ts_node_is_null(val)) { |
| 3936 | /* Synthesis: evaluate the RHS with the (possibly NULL) |
| 3937 | * annotated type as a hint. */ |
| 3938 | let_type = rust_eval_expr_typed(ctx, val, annotated); |
| 3939 | } |
| 3940 | if (!let_type) |
| 3941 | let_type = cbm_type_unknown(); |
| 3942 | if (!ts_node_is_null(pat)) |
| 3943 | rust_bind_pattern(ctx, pat, let_type); |
| 3944 | if (!ts_node_is_null(pat) && strcmp(ts_node_type(pat), "identifier") == 0 && |
| 3945 | !ts_node_is_null(val)) { |
| 3946 | char *binding_name = rust_node_text(ctx, pat); |
| 3947 | const char *value_kind = ts_node_type(val); |
| 3948 | const char *callable_qn = NULL; |
| 3949 | if (strcmp(value_kind, "identifier") == 0) { |
| 3950 | char *value_name = rust_node_text(ctx, val); |
| 3951 | if (value_name && cbm_scope_contains(ctx->current_scope, value_name)) { |
| 3952 | callable_qn = cbm_scope_lookup_callable(ctx->current_scope, value_name); |
| 3953 | } else if (value_name) { |
| 3954 | const char *resolved = rust_resolve_path_expr(ctx, value_name); |
| 3955 | const CBMRegisteredFunc *function = |
| 3956 | resolved ? cbm_registry_lookup_func(ctx->registry, resolved) : NULL; |
| 3957 | if (!function && resolved && ctx->module_qn) { |
| 3958 | function = cbm_registry_lookup_func( |
| 3959 | ctx->registry, |
| 3960 | cbm_arena_sprintf(ctx->arena, "%s.%s", ctx->module_qn, resolved)); |
| 3961 | } |
| 3962 | callable_qn = function ? function->qualified_name : NULL; |
| 3963 | } |
| 3964 | } else if (strcmp(value_kind, "scoped_identifier") == 0) { |
| 3965 | char *value_path = rust_node_text(ctx, val); |
| 3966 | const char *resolved = value_path ? rust_resolve_path_expr(ctx, value_path) : NULL; |
| 3967 | const CBMRegisteredFunc *function = |
| 3968 | resolved ? cbm_registry_lookup_func(ctx->registry, resolved) : NULL; |
| 3969 | callable_qn = function ? function->qualified_name : NULL; |
| 3970 | } |
| 3971 | if (binding_name && callable_qn) { |
no test coverage detected