ty 类型检查器 `unsound-return-statement` 规则:把 fully static 返回类型变成类型安全边界

发布时间:2026/9/10 1:57:38
ty 类型检查器 `unsound-return-statement` 规则:把 fully static 返回类型变成类型安全边界 ty 类型检查器unsound-return-statement规则把 fully static 返回类型变成类型安全边界【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruffunsound-return-statement是 ty本项目仓库中基于 Rust 实现的 Python 类型检查器提供的一条进阶 soundness lint 规则用于检测那些类型上可赋值、却并非子类型的不健全return语句——典型场景就是把一个被推断为Any的表达式直接返回给一个静态返回类型的函数。本文将完整讲解该规则的行为、触发边界、修复方式与底层实现帮助你在 Python 类型检查体系中构建更严格的类型化边界阻断Any在函数之间悄然渗透。规则概述它检查什么unsound-return-statement检测的是return语句所返回的类型并不是函数注解返回类型的[子类型]从而构成不健全unsound返回。这条 lint 是invalid-return-type的更严格版本invalid-return-type检查的是返回值根本无法赋值assignable给注解返回类型的情况unsound-return-statement进一步要求返回值必须是注解类型的子类型即使它能够通过赋值检查例如Any对int是可赋值的只要不是子类型就会报错。两者在 ty 的诊断体系中互为表里invalid-return-type对应更宽松的可赋值性检查unsound-return-statement对应更严格的子类型 完全静态检查。相关规则文档参见 invalid-return-type.md。为什么需要这条规则Any的静默渗透默认情况下类型检查器只要求返回值的推断类型**可赋值assignable**给函数注解的返回类型。问题在于Any类型与任何类型都可赋值于是只要代码里有一个表达式被推断为Any错误类型就可能顺着函数调用链悄悄扩散最终在运行时才暴露而类型检查器完全不会察觉from typing import Any def returns_any() - Any: return foo def returns_int() - int: # error: Unsound return statement: Any is not a subtype of int return returns_any() # fails at runtime, even though the type checker infers both operands as being of type int! returns_int() 42在这个例子中returns_any()的返回类型被推断为Any而Any可赋值给int所以默认检查不会报错但运行时returns_int()实际返回的是字符串foofoo 42直接抛出TypeError。启用unsound-return-statement后ty 会在returns_int中的return returns_any()处报错因为Any不是int的子类型。这相当于把每个声明了**完全静态fully static**返回类型的函数当作代码的类型化边界Any不允许无声无息地跨过这条边界不健全性必须在离源头本例中即returns_any的返回类型声明最近的位置被拦截。触发条件仅作用于 fully static 返回类型这条规则只应用于返回类型被注解为[完全静态fully static]的函数。如果返回类型中的任何位置出现Any或Unknown——无论是显式还是隐式——规则都不会触发from typing import Any def returns_any() - Any: return foo # error: [missing-type-argument] def returns_unparameterized_tuple() - tuple: # no error, since the return type is implicitly tuple[Unknown, ...] # (which is what the missing-type-argument error is complaining about on the line above!) return returns_any() def returns_list_of_any() - list[Any]: # no error, since the return type is explicitly list[Any] return returns_any()注意上述第二个例子中的微妙之处tuple未参数化的返回类型被隐式地视为tuple[Unknown, ...]其中含Unknown因此unsound-return-statement不触发——此时应该由另一条规则missing-type-argument来指出缺少类型参数这一更根本的问题。生成器函数的例外情形从实现上看ty 对生成器函数也应用同类检查在 function.rs 中若生成器的返回类型如Generator[int]是 fully static 类型则每个return语句同样要满足子类型要求否则报告 unsound return。也就是说fully static 类型化边界同样适用于生成器中的返回值。与其他规则的协同这条规则与 ty 的missing-type-argument、unsound-assignment规则配合得特别好也与 Ruff 的ANN201、ANN202、ANN204、ANN205、ANN206五条缺失返回类型注解规则互补。同时启用这些规则可以有效降低return语句把不健全性泄漏出函数的概率——除非该函数被显式地注解为动态类型如- Any或- tuple[Any]否则Any很难穿过返回类型边界unsound-assignment检查赋值给变量时值不是变量声明类型子类型的不健全赋值参见 unsound-assignment.mdunsound-yield检查yield/yield from表达式的值不是生成器注解 yield 类型子类型的不健全产出参见 unsound-yield.mdANN201等 Ruff 规则强制公开函数、私有函数、特殊方法、静态方法、类方法显式写出返回类型注解——只有注解存在才能形成可检查的类型化边界。从概念上看unsound-return-statement与 mypy 的no-any-return错误码是同类规则mypy 的--strict模式会启用它也可以单独通过--warn-return-any选项开启。示例与修复用类型收窄消除诊断触发示例from typing import Any def returns_any() - Any: return 42 def returns_int() - int: # error: Unsound return statement: Any is not a subtype of int return returns_any()修复方式在return之前把类型收窄narrow为int的子类型。通过assert isinstance(...)进行类型收窄后my_int的推断类型变为交集类型Any int而Any int是int的子类型因此不再报错from typing import Any from typing_extensions import reveal_type def returns_any() - Any: return 42 def returns_int() - int: my_int returns_any() assert isinstance(my_int, int) reveal_type(my_int) # revealed: Any int return my_int # no error: Any int is a subtype of int这也是 ty 在诊断中给出的修复建议在返回语句之前使用assert对类型进行收窄。源码实现诊断的生成逻辑规则的完整定义位于 diagnostic.rs其中记录了summary检测返回类型不是函数注解返回类型子类型的 return 语句statusLintStatus::stable(0.0.70)即自 ty 0.0.70 起作为稳定规则提供default_levelLevel::Ignore默认不启用。具体的诊断报告函数是report_unsound_return_statement见 diagnostic.rs。它的关键行为包括特殊注解归一化如果函数的返回注解是TypeIs或TypeGuard类型其实际返回类型归一化为bool这类函数被预期返回bool再参与后续比较与展示诊断消息简明消息为Unsound return statement: {actual} is not a subtype of {expected}并在返回类型位置附加辅助标注 Expected a subtype of ... because of the return type解释信息明确指出{actual} is assignable to {expected}, but not a subtype of {expected}说明可赋值但不健全的本质修复帮助help消息建议 Consider using anassertto narrow the type prior to thereturnstatement。触发路径先查赋值性再查子类型在函数体推断流程中ty 对每个显式return语句执行两级检查见 function.rs对每个 return 语句: 1. 若返回值 not assignable 到返回类型 - 报告 invalid-return-type 2. 否则若: - unsound-return-statement 规则已启用且 - 公共返回类型是 fully static 类型且 - 返回值不是返回类型的纯冗余pure redundancy类型 - 报告 unsound-return-statement其中TypeRelation::Redundancy { pure: true }表示纯冗余关系只有类型真正是返回类型的子类型时才算满足。这一实现同时处理了NotImplemented的特殊过滤先从联合类型中剔除NotImplemented再参与检查。代码注释还特别说明UNSOUND_YIELD和UNSOUND_ASSIGNMENT的实现与之几乎相同改动时需要同步更新——这印证了三条 unsound 规则在架构上的一致性。默认级别与适用人群unsound-return-statement默认是关闭的default_level: Level::Ignore需要用户显式启用。它的定位是为希望从类型检查器获得额外健全性保障的进阶用户设计而不是给刚刚开始对 Python 代码使用类型检查器的用户。理由很直接——它要求返回值是注解类型的子类型比业界常见的可赋值标准严格得多在大量存在Any交互的存量代码库中可能会产生较多噪音。对新手团队建议先用默认的invalid-return-type默认级别为Error保证基本的返回类型正确性当代码库的类型注解覆盖率足够高后再考虑启用unsound-return-statement与其配套规则把 fully static 返回类型真正变成不可穿透的类型安全边界。完整的规则文档可从 crates/ty/docs/rules.md 中的unsound-return-statement一节查看。相关规则速览规则检查对象与unsound-return-statement的关系invalid-return-type返回值无法赋值给注解返回类型本规则的宽松版默认启用Error 级别unsound-return-statement返回值不是注解返回类型的子类型本文主题默认禁用unsound-yieldyield/yield from值不是注解 yield 类型的子类型针对生成器的同类规则unsound-assignment变量赋值不是声明类型的子类型针对赋值的同类规则missing-type-argument泛型容器缺少类型参数隐式Unknown与隐式Unknown场景互补各规则的行为与边界可对照阅读 unsound-yield.md、unsound-assignment.md 与 invalid-return-type.md三者在文档与实现上互相印证共同构成 ty 的子类型级健全性检查家族。【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询