Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Incorrect type narrowing of `for` comprehension initial accumulator

未关闭
#15,980 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
38/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
elixir
领域
compilers

调研方向

Start by running both scripts from the issue as reduce_repro.exs and reduce_repro_1.exs to reproduce the false-positive type warnings. Trace the type handling for reduce: comprehensions in the compiler/type checker, using the gradual typing reference only to assess the documented alternative. Done means the initializer retains its input type and both examples execute without warnings while preserving their outputs.

由索引模型根据 Issue 内容生成。

描述

Existing issue
  • I have searched existing issues and could not find a duplicate.
Elixir and Erlang/OTP versions

Erlang/OTP 28 [erts-16.4.0.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Elixir 1.21.0-dev (7a40579)

Operating system

any

Current behavior

The current implementation types the initializer with the expected type of the comprehension result. An initializer is always evaluated but its value may never reach the final reduction result.

Repro:
save this as reduce_repro.exs and execute

    defmodule ReduceRepro do
      def calculate(initial) do
        (for _ <- [1], reduce: initial do
           _ -> 1
         end) + 1
      end

      def run, do: calculate(:old)
    end

    IO.inspect(ReduceRepro.run())

Result:
the code works fine and prints 2 but emits a false positive warning:

    warning: incompatible types given to calculate/1:

        calculate(:old)

    given types:

        :old

    but expected one of:

        float() or integer()

    type warning found at:
    │
  8 │       def run, do: calculate(:old)
    │                    ~
    │
    └─ reduce_repro.exs:8:20: ReduceRepro.run/0

another example:

defmodule ReduceRepro1 do
    def original(initial) do
      :ok =
        for _ <- [1], reduce: initial do
          _ -> :ok
        end

      case initial do
        :old -> :kept
        _ -> :other
      end
    end
end

IO.inspect(ReduceRepro1.original(:old))

result: code prints kept and warns

    warning: the following clause will never match:

        :old ->

    because it attempts to match on the result of:

        initial

    which has type:

        dynamic(:ok)

    type warning found at:
    │
 17 │         :old -> :kept
    │         ~~~~~~~~~~~~~
    │
    └─ reduce_repro_1.exs:17: ReduceRepro1.original/1

initial is incorrectly narrowed to dynamic(:ok)

I believe this is a separate problem from https://github.com/elixir-lang/elixir/issues/15451 - covers refinements inside conditional code branches

Expected behavior

Initializer type should not be narrowed. Precise typing is probably not possible as the reducer callback is not guaranteed to execute (as in #15451).
Alternatively, if the behaviour is intended it should be documented in https://github.com/elixir-lang/elixir/blob/main/lib/elixir/pages/references/gradual-set-theoretic-types.md#false-positives

主要语言
Elixir
星标
26.7k
派生
3.7k
平均合并
8 小时 7 分钟
30 天内合并 PR
60

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

elixir-lang/elixir 的其他 Issue

查看 elixir-lang/elixir 的全部 Issue

相似的 Issue

更多 Elixir Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。