Skip to content

Type checker: store x as <action call> raises ERROR "Could not infer type for variable" whenever the callee's return type is Unknown #588

Description

@logbie

Summary

store <var> as <call> emits an ERROR-level Could not infer type for variable '<var>' whenever the called action's return type is statically Unknown — which is the normal case for any action that returns an expression built from its (untyped) parameters. The program runs correctly and exits 0; only the static diagnostic is wrong, and it is very noisy.

This is the same gradual-typing philosophy as #567 (an Unknown value means "statically unknown", not "known incompatible"), but on the VariableDeclaration inference path, which #587 did not touch. It is not limited to list indexing — #567's inventory attributes the Could not infer type cascade to "indexing an untyped parameter", but the reproduction below has no lists or indexing at all.

Environment

Minimal reproduction

define action called add_one with parameters n:
    return n plus 1
end action

define action called use_it:
    store x as add_one of 3
    return x
end action

display use_it

Output (the program runs and prints 4):

Type checking warnings:
error[ERROR]: Could not infer type for variable 'x'
  ┌─ repro.wfl:6:5
  │
6 │     store x as add_one of 3
  │     ^ Type error occurred here

4

Exit code: 0 (non-fatal).

Note the severity/header inconsistency too: the block is titled Type checking warnings: but the item is labelled error[ERROR].

Scoping the trigger

Case RHS Result
store x as add_one of 3 where add_one returns n plus 1 (untyped param → Unknown return) Unknown Could not infer type for variable 'x'
store x as gives_text where gives_text returns "hello" (concrete return type) Text ✅ no diagnostic
display add_one of 3 — the same call used directly, no store ✅ no diagnostic

So the trigger is specifically binding an Unknown-typed call result to a variable with store. Callee-before-caller vs. callee-after-caller makes no difference (both fire).

Root cause

Statement::VariableDeclaration in src/typechecker/mod.rs treats an inferred Type::Unknown as an error:

// src/typechecker/mod.rs (~line 638)
if inferred_type == Type::Unknown && !is_container_property_assignment {
    self.type_error(
        format!("Could not infer type for variable '{name}'"),
        None, None, *_line, *_column,
    );
}

Under gradual typing, Unknown here means "statically unknown", which should bind x as Unknown silently — mirroring #587's own change for #567 ("Referencing a binding with no recorded type now yields Unknown silently instead of raising Cannot determine type of variable"). The VariableDeclaration arm just needs the same treatment: when inferred_type == Type::Unknown, record the variable as Unknown and do not raise a type_error.

Impact

Any action that returns an expression involving its parameters has an Unknown return type, so any caller that does store result as helper of ... gets flagged. In a real program built entirely from small mutually-recursive helpers, this dominates the output: the Scribe templating engine emits 104 of these notes on a fully-correct run (out of 106 total diagnostics), which drowns out anything real. Repro:

define action called wrap with parameters s:
    return "[" with s with "]"
end action
define action called go:
    store a as wrap of "x"      // Unknown return -> flagged
    store b as wrap of a        // flagged
    return b
end action
display go                       // prints [[x]], exit 0

Related

Suggested fix / test

In the VariableDeclaration arm, drop the type_error when inferred_type == Type::Unknown (bind the symbol as Unknown and continue). A regression test: the minimal repro above should type-check clean and run, printing 4 with no error[ERROR] on stderr.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions