Gleam v1.10.0 版本发布全解析:编译器诊断增强、语言服务器新特性与构建工具升级
【免费下载链接】gleam⭐️ A friendly language for building type-safe, scalable systems!项目地址: https://gitcode.com/GitHub_Trending/gl/gleam
导读
本文基于 Gleam 官方变更日志 changelog/v1.10.md 撰写,系统梳理 v1.10.0 与 v1.10.0-rc1 两个版本的核心更新,涵盖编译器(不可达分支检测、调用图驱动的未使用告警、位数组增强、类型错误信息优化、JavaScript 代码生成改进)、构建工具(gleam export新选项、erlang-shipment 双入口脚本、Hex 认证方式调整)、语言服务器(跨模块重命名、查找引用、十余项新 code action)以及容器镜像供应链安全等多个方面。读完本文,你将完整掌握 v1.10 的变更全貌,并理解这些功能在仓库源码中的落地实现。
版本时间线与发布节奏
v1.10 的发布遵循 Gleam 一贯的"先出候选版、再出正式版"节奏:
| 版本 | 发布日期 | 定位 |
|---|---|---|
| v1.10.0-rc1 | 2025-04-05 | 候选版,包含全部新特性与大部分 Bug 修复 |
| v1.10.0 | 2025-04-14 | 正式版,在 rc1 基础上追加了 2 项 Bug 修复 |
正式版相对候选版追加的修复包括:unqualify 类型/值的 code action 在已有导入的情况下会重复添加无限定导入的问题;以0x_、0o_、0b_开头的数字在编译到 JavaScript 时会触发语法错误的问题。下文先详述正式版修复,再按模块展开候选版引入的完整特性清单。
编译器:更智能的诊断与更稳的代码生成
不可达 case 分支现在会被警告
编译器现在能够判断字符串分支是否不可达。以下代码中,"Hello, " <> name这个前缀匹配分支已经覆盖了以"Hello, "开头的所有字符串,因此紧随其后的"Hello, Jak"分支永远不会被命中:
case a_string { "Hello, " <> name -> name "Hello, Jak" -> "Jak" _ -> "Stranger" }编译时会得到如下警告:
warning: Unreachable case clause ┌─ /src/greet.gleam:7:5 │ 7 │ "Hello, Jak" -> "Jak" │ ^^^^^^^^^^^^^^^^^^^^^ This case clause cannot be reached as a previous clause matches the same values. Hint: It can be safely removed.这项能力在源码层面由 compiler-core/src/exhaustiveness.rs 的穷举性/可达性分析支撑——该模块负责模式匹配的覆盖度检查,v1.10 将字符串前缀拼接(<>)的匹配关系纳入分析,从而推导出"前一条分支已匹配同样值"的结论。
调用图驱动的未使用检测,覆盖递归函数
v1.10 编译器改用调用图(call graph)来检测未使用的类型和值。这意味着此前难以判定的自递归但从未被外部调用的函数现在也能被准确识别:
// warning: unused fn some_recursive_function() { some_recursive_function() }在仓库中,调用图的构建实现在 compiler-core/src/call_graph.rs:该模块使用 petgraph 的有向图,将模块内的每个函数(CallGraphNode::Function)和常量(CallGraphNode::ModuleConstant)注册为图节点,遍历函数体与常量值中的引用关系建立边,再按依赖顺序分析可达性,未被任何入口引用到的节点即判定为未使用。这也是 v1.10 对"未使用代码"这一经典告警的算法级升级。
let assert恒定崩溃警告
当使用let assert断言一个变体已被推断出来的值时,编译器会提示该断言必然失败:
// warning: This will always crash let assert Ok(_) = Error("Some error")因为Error("Some error")的变体在构造时已经确定是Error,与Ok(_)模式必然不匹配,运行时必然 panic,编译器提前给出警告。
位数组(BitArray)的三项增强
- JavaScript 目标支持
unit选项:此前unit仅在 Erlang 目标生效,v1.10 起 JavaScript 目标下位数组的size选项可以配合unit使用来控制大小单位。 - 16 位浮点支持:JavaScript 目标下,表达式和模式中的位数组可以使用 16-bit floats(即半精度浮点)。
- 省略
:float选项:位数组段中的浮点字面量不再强制写:float,以下两种写法完全等价:
<<1.11>> <<1.11:float>>更友好的类型错误信息
v1.10 针对"选错运算符"这一最常见的类型错误给出了带修正建议的提示:
用+拼接字符串(应改用<>):
error: Type mismatch ┌─ /src/wibble.gleam:2:13 │ 2 │ "Hello, " + "Lucy" │ ^ Use <> instead The + operator can only be used on Ints. To join two strings together you can use the <> operator.对 Float 使用 Int 运算符(应改用+.):
error: Type mismatch ┌─ /src/prova.gleam:2:7 │ 2 │ 1.0 + 2.0 │ ^ Use +. instead The + operator can only be used on Ints.对 Int 使用 Float 运算符(应改用>):
error: Type mismatch ┌─ /src/prova.gleam:2:5 │ 2 │ 1 >. 2 │ ^^ Use > instead The >. operator can only be used on Floats.这些错误信息与语言服务器的自动修复 code action 配合(见下文),形成"报错 + 一键修复"的完整闭环。
二元运算符容错编译
二元运算符的编译现在是**容错(fault tolerant)**的:即使表达式存在类型错误,编译器也不会在第一个错误处停下,而是继续分析并报告所有同类错误,避免用户"改一个错、再冒出一个错"的反复编译。
函数标签相关错误收敛
当被调用的函数本身不存在时,编译器不再就它的标签(labels)继续报错,从而减少误导性的级联错误,让真正的问题(函数未定义)一目了然。
JavaScript 代码生成优化
JavaScript 目标下,块(blocks)及其他多种表达式不再编译为立即调用函数表达式(IIFE)。这既减少了生成代码的体积与嵌套层级,也让编译产物更贴近手写 JavaScript 的可读风格,便于调试与审查。
@target属性的错误信息改进
对@target属性中出现未知或缺失目标名的情况,编译器提供了更清晰的错误提示,帮助用户快速定位拼写错误或平台名不合法的问题。
构建工具与发布流程:更顺手的工程化体验
gleam new生成带类型注解的main函数
由gleam new脚手架生成的项目模板中,main函数现在带上了显式类型注解(pub fn main() -> Nil),使新项目的起步代码类型意图更明确,也方便在生成后直接改造为带参数或返回值的入口。
gleam export erlang-shipment始终生成双入口脚本
gleam export erlang-shipment现在总是生成两个入口脚本:
entrypoint.sh—— POSIX Shell 版本entrypoint.ps1—— PowerShell 版本
此前两种脚本的生成行为与平台相关,v1.10 起统一为跨平台各生成一份,方便用户在 Linux/macOS 与 Windows 上都能直接运行导出的 Erlang 发布包。实现上,compiler-cli/src/export.rs 的erlang_shipment函数在复制完各包的ebin、priv、include目录后,会调用write_entrypoint_script将模板中的$PACKAGE_NAME_FROM_GLEAM占位符替换为真实包名并写入输出目录(见 compiler-cli/templates/erlang-shipment-entrypoint.sh 与 compiler-cli/templates/erlang-shipment-entrypoint.ps1)。
生成的entrypoint.sh支持两个子命令:run(调用PACKAGE@@main:run(PACKAGE)运行项目 main 函数)与shell(进入 Erlang shell),未带参数或参数不合法时打印用法帮助。这使得导出的发布目录可以直接拷到装有 Erlang 的服务器上执行,无需任何构建工具链。
gleam export新增package-information选项
gleam export命令现在接受package-information选项,用于把项目的gleam.toml以 JSON 形式导出。其实现对应 compiler-cli/src/export.rs 中的package_information函数:读取根配置后调用docs::package_information_as_json(config)序列化为 JSON,可输出到指定文件或标准输出。这一能力对 CI 流水线、发布脚本等需要程序化读取项目元数据的场景非常实用。
Hex API key 的认证方式调整
两个与 Hex 发布认证相关的变更:
HEXPM_USER与HEXPM_PASS环境变量弃用:gleam publish时使用这两个变量进行认证的做法已被弃用,统一改用HEXPM_API_KEY。在 compiler-cli/src/hex/auth.rs 中可以看到HEXPM_API_KEY(写操作)与HEXPM_READ_API_KEY(只读操作)两个环境变量常量定义,本地存储的旧式 API key 会通过 OAuth 流程自动迁移(新 OAuth 令牌以本地密码加密保存)。- 本地 Hex API key 加解密失败的错误信息改进:当本地保存的 API key 加密/解密失败时,错误信息更明确,方便用户判断是密钥损坏还是本地密码不匹配。
HTML 文档结构优化
生成的 HTML 文档中,"functions"(函数)与 "constants"(常量)两个章节被合并为单一的 "values"(值)章节,文档导航更简洁,也减少了同一模块中函数与常量并列时的视觉割裂。
语言服务器:从"提示"到"自动改"
v1.10 的语言服务器(LSP)迎来一次大版本级的功能扩充,覆盖重命名、引用查找与十余个新 code action。相关实现分布在 language-server/src/rename.rs、language-server/src/reference.rs、language-server/src/code_action.rs 等模块中。
跨模块重命名
现在可以对函数、常量、自定义类型变体、自定义类型执行跨模块重命名。例如将wibble.gleam中的wibble函数重命名为wobble,另一模块wobble.gleam中的wibble.wibble()调用会同步更新为wibble.wobble(),且 import 语句保持正确:
// wibble.gleam pub fn wobble() { wobble() } // wobble.gleam import wibble pub fn main() { wibble.wobble() }查找引用
语言服务器新增对值(values)和类型(types)的引用查找能力,既支持模块内查找,也支持跨模块查找,与重命名、跳转定义共同构成完整的符号导航体验。
新 code action 一览
1. 展开模式中的..为全部被忽略字段
对let Pokemon(..) = todo中的..触发 code action,会展开为显式字段列表:
pub type Pokemon { Pokemon(id: Int, name: String, moves: List(String)) } pub fn main() { let Pokemon(id:, name:, moves:) = todo }2. "Generate JSON encoder" 改为结构感知
为自定义类型生成的 JSON encoder 从"逐字段展开"改为先解构再编码,一旦类型新增字段,生成的代码会编译失败,提醒开发者重新执行 code action,避免漏编码新字段:
fn encode_person(person: Person) -> json.Json { let Person(name:, age:) = person json.object([ #("name", json.string(name)), #("age", json.int(age)), ]) }3. 移除所有echo
可一键移除模块中的所有调试echo,既支持管道步骤形式(|> echo),也支持表达式前置形式(echo 1 + 2),删除后管道与表达式保持完整合法。
4. 运算符修正
- Float 运算符误用于 Int 值时,一键替换为正确的 Int 运算符:
11 +. 1→11 + 1; - Int 运算符误用于 Float 值时,一键替换为正确的 Float 运算符:
1.1 + 10.0→1.1 +. 10.0; - 用
+拼接字符串报错时,一键改为<>:"Hello, " + "Jak"→"Hello, " <> "Jak"。
这些 code action 与上文"更友好的类型错误信息"直接呼应:编译器负责准确报错并给出建议,语言服务器负责把建议一键落地。
5. 表达式提升为常量(const)
支持把表达式提取为模块级const,多次触发即可逐一提升:
const values = [#("a", 0), #("b", 1), #("a", 2)] const string = "a" pub fn main() { values |> key_filter(string) }6. 包裹为块(block)
选中 case 分支的右侧表达式或赋值表达式的值,可将其包裹进块中,方便继续添加多条表达式:
case pokemon_type { Water -> { soak() } Fire -> burn() }7. "Generate function" 智能命名参数
根据调用处的标签与变量名生成函数签名,例如greet(language, name: "Louis")会生成:
pub fn greet(language: String, name name: String) -> a { todo }8. 其余细节调整
- "Generate JSON encoder" code action仅在项目依赖中安装了
gleam_json包时提供,避免生成无法编译的代码; - "Rewrite from
use" code action 只在光标位于use表达式首行时触发,防止误触发。
容器镜像与供应链安全
容器镜像开始包含Software Bill of Materials(SBoM,软件物料清单)与SLSA Provenance(供应链出处证明)信息。这意味着基于 Gleam 官方容器镜像构建的应用,其依赖组成与构建出处可以被审计与验证,符合现代软件供应链安全(Supply Chain Security)最佳实践。
正式版 Bug 修复盘点
除上述新特性外,v1.10.0 还修复了一批影响日常开发的问题,按模块归类如下:
格式化与echo
- 修复
echo对首元素为原子(atom)的元组格式化不正确的问题; - 修复
echo在管道前使用时,Erlang 目标会生成非法代码的问题(v1.9.1 修复项,v1.10 延续); - 改进
echo打印管道的格式化效果(v1.9.1 修复项)。
构造器与参数
- 修复自定义类型变体构造器定义中,带标签参数之后允许出现不带标签参数的问题(v1.10 起禁止)。
Code action 相关
- 修复 "Convert to pipe" 在函数的第一个参数本身是管道时生成非法代码的问题;
- 修复 "Convert to pipe" 作用于函数或 record capture 时生成非法代码的问题;
- 修复 "Inline variable" 在 record update 内部使用时失效的问题;
- 修复 "Rewrite to pipe" 在管道参数是二元运算时生成非法代码的问题。
类型系统与模式匹配
- 修复
let assert赋值上变体推断不生效的问题; - 修复
let assert作为块内唯一表达式时不执行断言匹配的问题。
构建与缓存
- 修复文件被临时移动或删除后,即使依赖已变化也不会重新编译的问题;
- 修复构建工具锁定 build 目录失败但不报错的问题;
- 修复语言服务器过于积极地重新编译、未充分利用先前编译缓存的问题;
- 修复 build 目录被删除(如执行
gleam clean)后语言服务器停止工作的问题; - 修复发布时多顶层模块检查会误打警告的问题。
JavaScript 代码生成
- 修复
echo生成的 JavaScript 代码在模块内定义了console、process函数或Object、Deno自定义类型变体时发生名称冲突的问题。
语言服务器细节
- 修复补全(autocomplete)在模块选择(module select)场景下会建议 prelude 类型和值的问题;
- 修复 unqualify 类型/值的 code action 在目标已导入的情况下重复添加无限定导入的问题;
- 修复以
0x_、0o_、0b_开头的数字编译到 JavaScript 时报语法错误的问题。
小结与升级建议
v1.10 是一次典型的"编译器 + 工具链 + 编辑器体验"三位一体更新:编译器在诊断能力(不可达分支、未使用递归函数、运算符错误建议)与代码生成(IIFE 消除、位数组增强)上均有实质进展;构建工具在导出流程(双入口脚本、package-information)与发布认证(HEXPM_API_KEY)上更贴近实际部署场景;语言服务器则通过跨模块重命名、引用查找和一批高度实用的 code action,把"能提示"升级为"能自动改"。
对使用者而言,升级到 v1.10.0 后值得立刻验证的几件事:项目是否出现新的"未使用函数/不可达分支"警告(可能暴露存量死代码);发布脚本中是否仍依赖已弃用的HEXPM_USER/HEXPM_PASS(应尽快迁移到HEXPM_API_KEY);以及体验跨模块重命名与运算符修正 code action 带来的编辑效率提升。完整变更细节可查阅仓库内的 changelog/v1.10.md,各功能对应实现可继续深入 compiler-core/src/call_graph.rs、compiler-cli/src/export.rs 与 language-server/src/code_action.rs 等源码文件。
【免费下载链接】gleam⭐️ A friendly language for building type-safe, scalable systems!项目地址: https://gitcode.com/GitHub_Trending/gl/gleam
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考