Nimblesite / Nimblesite/Basilisk

calls_argument_type checks str.join arguments syntactically: 4 false positives on valid list displays, and a missed genuine error

Open
#356 0 comments 0 reactions 1 assignee View on GitHub

@abdushakoor12 is already working on this.

Since Jul 25, 2026.

Dominant language
Rust
Stars
54
Forks
3
PR merge metrics
No merged PRs in 30d

Description

Summary

calls_argument_type checks built-in method arguments against the syntactic shape of the expression (RhsKind), not against its type. For str.join, the effect is a rule that is wrong in both directions: it rejects valid code whenever a list/tuple/set display contains anything other than a string literal, and it silently accepts a genuinely wrong argument.

This is the remaining half of #332. The dict-display and returned-tuple cases from that report are fixed on main; the list-display cases are not, and the underlying cause is unrelated to the contextual-inference fix that closed the dict half.

False positives

Every line below is valid Python and valid typing. All four are flagged.

def f(p: list[str], s: str) -> None:
    " ".join(["a", *p])       # error — unpack element (the case reported in #332)
    " ".join(["a", s])        # error — plain `str` variable element
    " ".join([s.upper()])     # error — method call element
    " ".join(("a", s))        # error — tuple form
error[calls_argument_type]: Argument `iterable` of `join` expects `Iterable[LiteralString] | Iterable[str]`
but received an argument incompatible with `Iterable[LiteralString] | Iterable[str]` (List([StrLiteral, Other]))

These pass, which is why it hides until a variable is involved:

" ".join(p)                   # OK — bare name
" ".join(["a", "b"])          # OK — all literals
" ".join([f"{s}!"])           # OK — f-string

False negative, from the same defect

def g(nums: list[int]) -> None:
    " ".join(nums)            # genuine type error — NOT reported

A bare name is RhsKind::Other and Other is accepted unconditionally at the top level, so the declared list[int] is never consulted.

Relatedly, " ".join(["a", n]) with n: int is reported — but only by accident. n classifies as Other, exactly like the valid s: str case above, and the emitted diagnostic is byte-identical. The rule cannot distinguish them.

Cause

stub_argument_compatible, in the Iterable[str] | Iterable[LiteralString] branch:

RhsKind::StrLiteral | RhsKind::EmptyList | RhsKind::Other
| RhsKind::CallExpr | RhsKind::KnownCall(_) => true,            // unknown ⇒ accept
RhsKind::List(items) | RhsKind::Tuple(items) | RhsKind::Set(items) => {
    items.iter().all(|item| matches!(item, RhsKind::StrLiteral))  // elements: literals only
}

Other and CallExpr are given the benefit of the doubt at the top level, but the same kinds are rejected one level down as elements. The benefit-of-the-doubt policy simply stops at the container boundary. Since no branch resolves an element to a type, a correct list[str] and an incorrect list[int] are indistinguishable once they reach the element check.

Expected

  • The four false-positive forms check cleanly.
  • " ".join(nums) with nums: list[int] is reported.
  • The negative controls that already work keep working: " ".join([1, 2]) still errors.

The fix is to resolve each element's declared type rather than matching on syntax; that closes the false positives and the false negative together. Extending the top-level "unknown ⇒ accept" rule to elements would silence the false positives alone, but would leave join unable to catch anything real.

Message quality

The rendered type is a Rust Debug of an internal enum, printed to the user verbatim at calls_argument_type.rs:157 (format!("... ({rhs:?})")):

(List([StrLiteral, Other]))

Other is meaningless to a user and List([...]) is not Python syntax. This should render a Python type.

Version

Reproduced identically on released 0.37.3 and on main @ adb158df (0.0.0-PLACEHOLDER) — 4 false positives and 1 false negative on both, so this is not a regression from the #332 work.

Repro lives at issue-332-dict-literal/app.py in the repro workspace (lines 76, 87, 117).

Refs

Refs #332

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.