Gleam v1.17 全版本解析:编译器容错、构建工具增强与语言服务器代码动作大升级
【免费下载链接】gleam⭐️ A friendly language for building type-safe, scalable systems!项目地址: https://gitcode.com/GitHub_Trending/gl/gleam
导读
Gleam v1.17.0(2026-06-02 发布)是语言工具链的一次大规模迭代,横跨编译器(compiler)、构建工具(build tool)与语言服务器(language server)三大组件,累计包含 60 余项变更。本篇基于仓库内 changelog/v1.17.md 的完整记录,并结合 compiler-core、compiler-cli、language-server 的源码实现,逐一拆解这些改进背后的原理与用法。读完本文,你将掌握 v1.17 引入的新命令(如gleam export escript)、新标志(如gleam dev --no-print-progress)、依赖检查输出格式变化,以及十余个新的语言服务器代码动作与诊断容错机制,并了解其对应的源码位置,便于深入验证与二次开发。
说明:该版本发布于 2026 年,包含 v1.17.0-rc1(2026-05-23)与 v1.17.0-rc2(2026-06-01)两个预发布阶段,最终 v1.17.0 汇总了全部修复。发布辞将本版本献给 Chris Young,纪念其对 Gleam 社区的启发与支持。
一、v1.17.0 正式版:安全加固(Bug Fixes)
正式版的三项变更全部围绕安全与数据完整性展开,均属于"收紧边界"性质的行为变化:
- 限制自定义文档页面的
path与source值:gleam docs build不再允许通过自定义文档页面配置逃逸文档输出目录或项目根目录,从根上杜绝了文档构建阶段的目录穿越(path traversal)风险。相关生成逻辑位于 compiler-core/src/docs.rs,构建命令入口在 compiler-cli/src/docs.rs。 - 构建目录内部文件的更严格反序列化规则:
build目录内缓存文件(manifest 等)的解析现在会拒绝损坏或格式异常的数据,避免损坏缓存导致后续步骤行为异常。相关解析逻辑集中在 compiler-cli/src/dependencies/dependency_manager.rs 与 compiler-cli/src/build_lock.rs。 - 发布 tarball 内容边界收紧:
gleam publish打包时不再允许将项目根目录之外的文件纳入发布包,防止隐私文件或无关文件被意外发布到 Hex。打包逻辑位于 compiler-cli/src/publish.rs。
二、编译器(Compiler):更聪明的诊断与更稳健的推断
2.1 未知变量建议:从导入模块中给出候选项
当引用了不在作用域内的变量时,编译器现在会基于名称与元数(arity),从已导入模块中检索同名的公共值并给出建议。以 changelog 中的示例:
import gleam/io pub fn main() -> Nil { println("Hello, World!") }编译器会输出:
error: Unknown variable ┌─ /path/to/project/src/project.gleam:4:3 │ 4 │ println("Hello, World!") │ ^^^^^^^ The name `println` is not in scope here. Did you mean one of these: - io.println从源码看,这一能力由Error::UnknownVariable变体中的possible_modules字段承载,其注释明确写着"Filled with the name of imported modules when the module has public value with the same name as this variable",定义于 compiler-core/src/type_/error.rs。配套的类型检查测试覆盖了多条边界:不会建议其他包中的内部函数/构造器/类型/值、不会建议私有成员等,参见 compiler-core/src/type_/tests/errors.rs 一带的unknown_variable_do_not_suggest_*系列用例。
2.2 类型推断容错:错误不再"雪崩"
v1.17 显著提升了编译器在部分出错时的分析韧性:
- 记录更新(record update)容错:若被更新的记录本身存在错误,编译器仍能继续分析用户提供的字段。这意味着 IDE 中写
Person(..mom, age: 61)时,即使mom的类型有问题,age字段的类型校验依然会执行,错误提示更聚焦。 - 子句守卫(clause guard)容错:守卫表达式某一部分出错时,编译器会继续分析守卫的其余部分,而不是在第一个错误处停下。这与类型检查管线中错误累积的设计一致(相关推断路径在 compiler-core/src/type_/expression.rs 与 compiler-core/src/type_/guard.rs)。
这两项改进共同减少了一处错误引发"连锁报错"的体验问题。
2.3 常量(constant)中的todo关键字
此前在常量里写todo会直接得到语法错误;v1.17 起该写法被显式解析,并在类型检查阶段给出友好的TodoConstant诊断(This code is incomplete风格提示)。实现证据:
- 解析测试:compiler-core/src/parse/tests.rs(
missing_todo_constant_message); - 类型检查报错:compiler-core/src/type_/constant.rs(
Error::TodoConstant); - 诊断渲染:compiler-core/src/error.rs(
TypeError::TodoConstant)。
同时在代码生成阶段(Erlang 与 JavaScript 后端)若遇到Constant::Todo会触发panic!("todo constants should not reach code generation"),即编译器保证todo常量不会流入产物,见 compiler-core/src/erlang.rs 与 compiler-core/src/javascript/expression.rs。
2.4 警告中的类型名正确限定
编译器打印警告(如 "Todo found")时,类型提示现在会按当前模块的导入方式正确显示限定或别名后的类型名。changelog 给出的例子:
import user pub fn main() { user.to_string(todo) |> io.println }警告中Hint: I think its type isuser.User.中的user.User与源码中的模块限定一致,不再出现"警告里显示的类型名与代码里写的不一样"的困惑。
2.5 常量记录的容错与最小版本跟踪
- 空参数列表的常量记录不再中断模块分析:此前写
pub const x = Foo()(构造器参数列表为空)会导致整个模块停止分析,v1.17 修复为仅报告局部错误后继续。 - 常量中使用列表前插(list prepending)时正确跟踪最低 Gleam 版本:修复了此前不记录
[1, ..xs]这类语法在常量中所要求的最低编译器版本的问题。
2.6 JavaScript 后端的代码生成优化
v1.17 对 JavaScript 目标做了多项质量与正确性改进:
- 剩余字节位数组检查规范化:对字节对齐模式生成更统一的代码——当常量偏移
c与 8 同余时,(bitSize - c) % 8 === 0被规范化为bitSize % 8 === 0,产出更简洁、更可读的 JS。 let解构穷尽模式生成更精简:对用let做穷尽性解构的代码,减少冗余临时变量与分支。- 修复了若干正确性缺陷(详见下文"Bug 修复"章节):分号缺失、重复
let声明(pipeline 中case作为步骤、或 subject 直接匹配分支时)、导入的零参数变体与导入别名在相等比较中的构造函数名错误。
三、构建工具(Build tool):新命令、新标志与新体验
3.1gleam dev --no-print-progress:静默进度输出
gleam dev命令新增--no-print-progress标志,传入后不再打印任何进度信息,适合在脚本化或持续集成场景中保持输出干净。
从源码看,该标志在整个 CLI 中广泛存在:它定义于 compiler-cli/src/lib.rs 的Build子命令(以及 L346-347、L381-382 处的其他命令),并经由no_print_progress_doc()(compiler-cli/src/lib.rs)生成帮助文本。实际生效机制是:当标志为真时,build流程改用不输出进度事件的Telemetry实现,见 compiler-cli/src/build.rs;run命令也有同样处理(compiler-cli/src/run.rs)。
3.2gleam deps outdated:强制输出摘要
gleam deps outdated现在始终打印一行摘要,说明共有多少包有可用新版本:
$ gleam deps outdated 1 of 12 packages have newer versions available. Package Current Latest ------- ------- ------ gleam_stdlib 0.70.0 0.71.0当全部依赖都是最新时,只输出摘要行:
$ gleam deps outdated 0 of 12 packages have newer versions available.实现上,该命令读取 manifest 中source为 Hex 的包,异步向 Hex 查询版本并计算差异,最终由pretty_print_outdated_versions组装输出——其逻辑为"总是先打印N of M packages have newer versions available.摘要,仅当存在更新时追加表格",见 compiler-cli/src/dependencies.rs;入口函数outdated在 compiler-cli/src/dependencies.rs。对应的单元测试位于 compiler-cli/src/dependencies/tests.rs,覆盖了"有更新"与"无更新"两种输出形态。
3.3 Hex 会话失效:专属错误与自动重新认证
当 Hex 会话(API key/token)被撤销或过期时,包管理器现在会给出针对性错误信息,并走自动重新认证流程,而不是笼统地报一个难以理解的失败。相关认证实现位于 compiler-cli/src/hex/auth.rs。
3.4gleam export escript:单文件 BEAM 可执行程序
这是 v1.17 最亮眼的新功能:将 Gleam 程序打包为escript——即把编译后的 BEAM 字节码与运行时信息合并进单个可执行文件,便于分发 CLI 工具。
从 compiler-cli/src/export.rs 的实现可以看清完整流程:
- 以Erlang 目标、生产模式(
Mode::Prod)重新构建项目,并强制要求存在main函数(get_main_function找不到会直接报错); - 遍历构建产物中每个包目录的
ebin,把其中所有.beam字节码与.app应用配置打包进一个 zip 归档; - 在项目根目录生成以包名命名的可执行文件,头部写入:
#!/usr/bin/env escript %% %%!-escript main {package_name}@@main其中
-escript main {package_name}@@main指示 BEAM 的 escript 运行时调用 Gleam 标准入口模块; - 追加 zip 归档并设置可执行权限;
- Windows 下额外生成
{package_name}.cmd包装脚本(@echo off\r\nescript.exe "%~dpn0" %*\r\n),因为 Windows shell 不识别 shebang。
命令在 CLI 中注册于 compiler-cli/src/lib.rs(export::escript)。使用方式:
gleam export escript # Your escript has been generated to ./my_package.要求本机具备 Erlang 的escript运行时;产物依赖 BEAM 虚拟机执行,因此目标机也需要 Erlang/OTP 环境。
3.5 发布与模板细节
- monorepo 中的 Git 仓库发现:
gleam publish现在能更好地在 monorepo 结构中发现 Git 仓库,从而在没有 tag 时给出更准确的"请推送 tag"提示。 manifest.toml注释更新:gleam deps生成的 manifest.toml 注释现在明确建议用户将 manifest 文件纳入版本控制(源码控制)仓库。- 新项目默认 Erlang/OTP 29:
gleam new生成的新项目,其 GitHub Actions 模板现在请求 Erlang/OTP 版本 29。
3.6 发布工件:gleam-licences.html
每个版本现在随发布附带gleam-licences.html,详细列出所使用依赖的许可证信息,便于合规审计(对应 licences 目录中收录的各类开源许可证文本)。
四、语言服务器(Language server):一批新的代码动作与补全
v1.17 的语言服务器改动量最大,新增了 7 个左右的代码动作/补全能力,并修复了大量"错误时机弹出动作"的体验问题。
4.1 "Fill labels":常量构造器自动补全标签参数
对常量中的记录构造器,若遗漏了带标签参数,现在可通过 "Fill labels" 代码动作自动补齐为todo:
pub type Pokemon { Pokemon(number: Int, name: String, hp: Int) } pub const cleffa = Pokemon(number: 173)触发动作后变为:
pub const cleffa = Pokemon(number: 173, name: todo, hp: todo)该动作的测试非常完备,见 language-server/src/tests/action.rs 一带的fill_labels_*系列:它会优先使用作用域内类型匹配的变量(fill_labels_uses_variable_in_scope_with_matching_type)、在无匹配类型时回退到todo(fill_labels_falls_back_to_todo_when_type_does_not_match)、忽略下划线前缀变量、忽略定义在调用之后的变量、处理外层作用域遮蔽、case 模式中的变量、泛型类型匹配,甚至支持在模式构造器中触发(L10647 起)。
4.2 记录更新悬停:显示未更新的字段
悬停在记录更新表达式(Person(..mom, age: 61)中的..mom)上时,会列出没有被更新、继承自原记录的字段:
pub type Person { Person(name: String, age: Int) } pub fn happy_birthday_mom() { let mom = Person(name: "Antonella", age: 60) Person(..mom, age: 61) // ^^^^^ Hovering this will show: // Unchanged fields: // - name }4.3 补全:列表尾部与记录更新
列表尾部补全:在写
[..时,作用域内的列表变量会被建议:pub fn main() { let things_i_like = ["Gleam", "Ice Cream"] ["Dogs", ..t|] // ^ 建议 `things_i_like` }记录更新补全:在写
User(..时建议作用域内的User类型变量:pub fn set_name(user: User, name: String) -> User { User(..u|) // ^ 建议 `user` }
4.4 移除冗余记录更新
当记录更新的所有字段都已显式给出(..实际上没有继承任何字段)时,会触发警告,并可用代码动作直接删掉冗余部分:
pub fn main() { let lucy = User(name: "Lucy", likes: ["Gleam", "Ice Cream"]) let jak = User(..lucy, name: "Jak", likes: ["Gleam", "Dogs"]) // ^^^^^^ This record update is not needed! }动作后变为:
let jak = User(name: "Jak", likes: ["Gleam", "Dogs"])4.5 守卫中错误运算符的自动修复
Gleam 没有运算符重载,字符串拼接用<>而非+。当在守卫中误用+拼接字符串时,语言服务器会给出可一键应用的修复:
case pokemon { Pokemon(name:, ..) if name == "rai" + "chu" -> todo _ -> todo }触发代码动作后+被替换为<>。
4.6 在 discard(_)上继续模式匹配
对一个被丢弃的模式(如Ok(_))触发代码动作,可将其展开为它实际丢弃的具体模式分支:
case x { Error(Nil) -> io.println("no names") Ok(_) -> todo }变为:
case x { Error(Nil) -> io.println("no names") Ok([]) -> todo Ok([first, ..rest]) -> todo }4.7 引用查找与文档高亮
- 别名导入的 find references:光标放在别名导入(
import gleam/io.{println as log})的别名log上触发 "find references",会显示io.println()的所有引用。 documentHighlight全面支持:凡是references可用之处,现在都支持高亮——光标放在任一vec实例上,会高亮函数内所有vec出现位置(包括访问字段的表达式)。
4.8 其余语言服务器改进
- 快速修复优先呈现:quick fix 类代码动作现在排在重构类动作之前,减少干扰。
- Generate variant 自动补 import:在非当前模块生成 variant 时,自动为生成位置所在的模块添加对应 import。
- 不显示依赖中的废弃值补全:依赖包中被标记
@deprecated的值不再出现在补全列表中。 - 创建未知模块:当
import wobble/woo引用了不存在的模块时,触发代码动作可创建src/wobble/woo.gleam。 - 修复了"Convert to case"对非首个inexhaustive
let静默失败、以及多case模块中 "add missing patterns" 不出现的问题。
五、Bug 修复汇总(按主题归类)
5.1 命令与包管理
gleam remove无 manifest 时的错误信息:若manifest.toml不存在(新项目或已被删除),此前会报出令人困惑的 File IO 错误;现在给出清晰的提示。gleam update误查本地/git 依赖:修复了gleam update会对本地路径或 git 来源的依赖去 Hex 检查"新主版本"的问题。gleam publish的 OTP 应用名元数据:当依赖的 Hex 包名与内部 OTP 应用名不一致时,发布包元数据中写入了错误的应用名,导致依赖这些包的 Mix 项目在遇到传递依赖时构建失败——现已修复。- 代理 + 自签名证书的 HTTPS 连接:CLI 现在默认使用系统信任库中的受信 CA,可在使用自签名证书的代理网络环境中完成 HTTPS 连接。
5.2 位数组(BitArray)诊断与生成
- 修复:JS 后端
bytes与unit选项同时使用时可能生成错误代码。 - 修复:带
unit选项的BitArray段中超过 JS 安全整数上限的 int 缺少警告,以及非 int 的 byte 段被误报警告。 - 改进错误信息:常量位数组的大小非字面量数字、非法
unit、非法 segment,以及@external/@deprecated注解参数不是字符串时,均给出更易理解的诊断。
5.3 语言服务器代码动作的触发时机
v1.17 集中修复了一批"代码动作在不该出现的地方出现"的问题:wrap in anonymous(未悬停函数/悬停记录更新时)、convert to case(未悬停 inexhaustive let 时)、add missing pattern(未悬停 inexhaustive case 时)、unqualify / qualify(未悬停对应对象时)、generate dynamic decoder / generate json encoder / missing type parameter / unwrap anonymous(未悬停 custom type 时)、extract function(选中 case 多分支或模式/守卫时)——这些动作现在只在正确的悬停/选择上下文中出现。
5.4 编译器与配置
javascript.typescript_declarations/javascript.source_maps配置变更后自动重建:此前修改这两项配置后若不手动删除build目录,附加文件(.d.ts、source map)不会被生成;现在配置变化会触发自动重建。- 常量构造器提取为变量:修复了语言服务器不允许把记录构造器提取为变量的缺陷。
- prelude 补全的类型过滤:来自语言 prelude 的值若与当前上下文类型不兼容,不再出现在补全中。
- 守卫中带尾部的列表:修复了守卫里使用带尾部列表模式时生成无效代码的问题。
六、升级与验证建议
- 获取本版本后先运行
gleam deps outdated查看依赖状况,新摘要行便于脚本解析(N of M packages have newer versions available.)。 - 需要分发单文件 CLI 时,尝试
gleam export escript,产物位于项目根目录,文件名为包名;注意其要求项目存在main函数且本机具备 escript 运行时。 - 语言服务器使用者可立刻体验新代码动作:在常量上触发 "Fill labels"、在
Ok(_)上展开模式、用User(..补全记录更新,并注意快速修复与重构类动作的排序变化。 - 若在代理环境下遇到 HTTPS 连接失败,请确认 CLI 已默认走系统信任库(v1.17 行为),无需额外配置。
- 本文所引源码均为当前仓库主分支实现(compiler-cli/src/export.rs、compiler-cli/src/dependencies.rs、compiler-core/src/type_/error.rs、language-server/src/tests/action.rs 等),可作为深入研读的起点;变更原文见 changelog/v1.17.md,更早版本可对照 changelog 目录下的 v1.1~v1.16 记录了解演进脉络。
【免费下载链接】gleam⭐️ A friendly language for building type-safe, scalable systems!项目地址: https://gitcode.com/GitHub_Trending/gl/gleam
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考