Skip to content

Parser crashes on charlist with pure interpolation ('#{x}') #132

@moxley

Description

@moxley

Spitfire 0.3.11 raises FunctionClauseError when parsing a charlist literal whose only content is a string interpolation segment.

Repro

Mix.install([{:spitfire, "~> 0.3"}])
Spitfire.parse(~S|defmodule D, do: '#{x}'|)

Stack trace

** (FunctionClauseError) no function clause matching in String.to_charlist/1
    # 1
    {{1, 19, nil}, {1, 22, nil}, [{:identifier, {1, 21, ~c"x"}, :x}]}
    (elixir 1.17.3) lib/string.ex:2847: String.to_charlist/1
    (spitfire 0.3.11) lib/spitfire.ex:2480: Spitfire.parse_string/1

Root cause

The :list_string non-interpolation clause of parse_string/1 (lib/spitfire.ex:2480) is missing the when is_binary(string) guard that the parallel :bin_string clause at line 2463 has. When the tokenizer emits a single-element token list for a charlist that is pure interpolation, the unguarded clause matches and String.to_charlist/1 is called on the interpolation-segment tuple.

Charlists with surrounding text ('foo#{x}bar') were unaffected because their token list has multiple elements and falls through to the interpolation-aware clause.

Scope

Input 0.3.11
'foo' OK
'foo#{x}bar' OK
'#{x}' crash
"#{x}" OK
heredoc charlist OK
heredoc bin OK

Also affects downstream xp_spitfire (vendored by Expert LSP) and breaks
Go-to-Definition on files containing this construct. Hit naturally in e.g.
plug_forwarded_peer's lib/plug_forwarded_peer.ex.

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