资讯动态

Ruff ty 类型检查器中的类型变量作用域规则:从 typing 规范到 mdtest 的完整实现解析

发布时间:2026/9/10 14:19:40 来源:尧图企业网站定制
Ruff ty 类型检查器中的类型变量作用域规则从 typing 规范到 mdtest 的完整实现解析【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff导读本文聚焦于 ruff 仓库中ty类型检查器对泛型类型变量type variable作用域规则的实现与测试验证。以 crates/ty_python_semantic/resources/mdtest/generics/scoping.md 这份测试文档为骨架完整覆盖了从“未绑定类型变量unbound-type-variable”到“类型变量遮蔽shadowed-type-variable”、“类型参数默认值越界invalid-type-variable-default”等二十余种场景并结合ty_python_semanticcrate 的源码与 lint 定义说明这些规则在 Rust 实现层面是如何落地、如何被诊断diagnostic系统报告的。读完本文你将掌握ty对 Python typing 规范中泛型作用域的全部行为约定并能直接阅读、运行和扩展对应的 mdtest 用例。背景这份文档在仓库中的角色scoping.md位于 crates/ty_python_semantic/resources/mdtest/generics/ 目录下属于ty_python_semanticcrate 的mdtestMarkdown 驱动测试体系。这类文档中的每一个 Python 代码块都会被打包成独立测试用例配合reveal_type的期望输出、# error: [diagnostic-name]注释以及内联 snapshot直接驱动类型检查器执行并校验诊断结果。运行这些测试的入口是 crates/ty_python_semantic/mdtest.py它会先通过cargo test --package ty_python_semantic --testmdtest编译测试再调用编译产物逐个执行 Markdown 中提取的用例并支持--enable-external、--no-snapshot-updates等参数控制外部依赖测试、lockfile 升级与 snapshot 更新。整个文档头部声明的[environment] python-version 3.12在类型参数默认值章节切换为3.13正是为每个用例设置的解释器版本环境。注意文中大量测试用例来源于 PEP 695 泛型语法 与 typing 规范的 Scoping rules for type variables 章节仓库作者在此基础上补充了更一般的规则假设见“嵌套正式类型变量必须互异”一节。类型变量只能在泛型上下文使用unbound-type-variable基本规则typing 规范规定类型变量只能出现在泛型函数或泛型类的定义中。scoping.md开篇即验证了三种“越界”用法都会触发unbound-type-variable诊断from typing import TypeVar T TypeVar(T) # error: [unbound-type-variable] x: T class C: # error: [unbound-type-variable] x: T def f() - None: # error: [unbound-type-variable] x: T无论模块顶层、类体还是普通函数体内只要类型变量没有被任何泛型作用域绑定就属于非法使用。源码层面的 lint 定义该诊断在 crates/ty_python_semantic/src/types/diagnostic.rs 中声明declare_lint! { #[doc include_str!(../../resources/lint_docs/unbound-type-variable.md)] pub(crate) static UNBOUND_TYPE_VARIABLE { summary: detects type variables used outside of their bound scope, status: LintStatus::stable(0.0.20), default_level: Level::Error, } }其语义文档位于 crates/ty_python_semantic/resources/lint_docs/unbound-type-variable.md检查“在未被任何泛型上下文绑定的作用域中使用类型变量”的情况因为这种用法没有明确定义的含义。构造函数调用必须使用已绑定的类型变量类型检查器在解析list[T]()这类构造调用时要求其中的类型实参必须在某个包围的泛型作用域中已绑定。特别地赋值不引入泛型上下文items list[T]()同样是错误嵌套类型实参遵循同一规则list[list[T]]()中内层T同样越界自定义泛型类同样受限Box[T]()Box(Generic[T])也会报unbound-type-variable。from typing import Generic, TypeVar T TypeVar(T) # error: [unbound-type-variable] list[T]() # error: [unbound-type-variable] items list[T]() # error: [unbound-type-variable] list[list[T]]() class Box(Generic[T]): ... # error: [unbound-type-variable] Box[T]()作为对照泛型函数和泛型类可以使用自己的类型变量来调用构造函数两种语法legacyTypeVar与 PEP 695[T]行为一致def make(value: T) - list[T]: result listT reveal_type(result) # revealed: list[Tmake] return result class Factory(Generic[T]): def make(self, value: T) - list[T]: return listT def modernT - list[T]: return listT值得注意的是reveal_type(result) # revealed: list[Tmake]这里Tmake表示该类型变量绑定于make函数的泛型上下文是ty检查器用来区分不同绑定实例的命名约定。例外类型别名赋值与类基列表可以引入泛型上下文Alias list[T] reveal_type(Alias[int]()) # revealed: list[int] Alias() class Derived(list[T]): ...Alias list[T]这条类型别名赋值会引入一个携带T的泛型上下文因此Alias[int]()与不带显式类型实参的Alias()都合法class Derived(list[T])同理。这与“赋值给变量不引入泛型上下文”形成对比——区别在于别名赋值产生的是类型级绑定而不是值级绑定。存根.pyi中的一致行为scoping.md用独立的pyi代码块验证存根文件里的构造调用遵循与.py源码完全相同的规则list[T]()和items list[T]()在.pyi中同样报unbound-type-variable。类型变量的推断实例化语义Legacy 语法同一类型变量可被多次推断为不同类型A type variable used in a generic function could be inferred to represent different types in the same code block.legacyTypeVar语法下同一个模块级T可以被不同函数分别绑定互不影响from typing import TypeVar T TypeVar(T) def f1(x: T) - T: return x def f2(x: T) - T: return x f1(1) f2(a)这里不产生任何诊断f1的T与f2的T在推断时是两个独立的实例化。同一函数多次调用每次调用独立实例化这一规则也适用于同一个泛型函数被多次调用的情况——每次调用都把类型变量实例化为不同的具体类型def fT - T: return x reveal_type(f(1)) # revealed: Literal[1] reveal_type(f(a)) # revealed: Literal[a]PEP 695 语法下f(1)推断出Literal[1]、f(a)推断出Literal[a]证明类型变量在每次调用时被独立地求解。类方法中的类型变量绑定语义方法可以提及类的类型变量A type variable used in a method of a generic class that coincides with one of the variables that parameterize this class is always bound to that variable.类C[T]的方法中出现的T恒等于类的类型变量由接收者receiver决定class C[T]: def m1(self, x: T) - T: return x def m2(self, x: T) - T: return x c: C[int] C[int]() c.m1(1) c.m2(1) # error: [invalid-argument-type] Argument to bound method C.m2 is incorrect: Expected int, found Literal[string] c.m2(string)当c被注解为C[int]后c.m2(string)被精确诊断为“期望int实际为Literal[string]”说明T已随类特化被固定为int。把已绑定的类类型变量传给更宽泛的参数类型检查器必须遵守一条关键规则类类型变量由接收者固定不得从参数注解反向推断出新的特化。以带 bound 的类型变量为例class G[T: int]: def takes_object(self, value: object) - None: ... def echo(self, value: T) - T: return value def caller(self, value: T, other: G[int]) - None: self.takes_object(value) other.takes_object(value) reveal_type(self.echo(value)) # revealed: TG # error: [invalid-argument-type] Expected int other.echo(bad) def explicit_receiver(self: G[T], value: T) - None: self.takes_object(value)把T值传给object参数是合法的类型变量值当然可以赋值给object但这不意味着从takes_object的参数注解推导出什么新信息self.echo(value)的结果仍保持TG的符号形式。同时other: G[int]已被特化为int因此other.echo(bad)报错。explicit_receiver(self: G[T], value: T)则展示了通过显式Self注解绑定T的写法同样成立。相同的规则适用于classmethod与__contains__触发的成员测试class Container[T: int]: classmethod def takes_object(cls, value: object) - None: ... def __contains__(self, value: object) - bool: return False def caller(self, value: T) - None: self.takes_object(value) self.__contains__(value) reveal_type(value in self) # revealed: bool扩展到 bound 的父类、约束类型变量与 legacy 语法scoping.md进一步验证了三个推广场景1参数不必是objectbound 的任意父类都接受其值class Base: ... class Child(Base): ... class G[T: Child]: def takes_base(self, value: Base) - None: ... def caller(self, value: T) - None: self.takes_base(value)2约束constrained类型变量每个允许的特化都可赋值给object而无需在方法调用处重新挑选某个约束class G[T: (int, str)]: def takes_object(self, value: object) - None: ... def echo(self, value: T) - T: return value def caller(self, value: T) - None: self.takes_object(value) reveal_type(self.echo(value)) # revealed: TG3legacy 类类型变量遵循同样的规则from typing import Generic, TypeVar T TypeVar(T, boundint) class G(Generic[T]): def takes_object(self, value: object) - None: ... def caller(self, value: T) - None: self.takes_object(value)泛型类上的函数是描述符特化贯穿描述符协议这一节在 crates/ty_python_semantic/resources/mdtest/call/methods.md 的“函数即描述符”测试基础上重复到泛型类上以确认特化信息能完整地穿过描述符协议self参数正是通过它绑定到实例方法的from inspect import getattr_static class C[T]: def f(self, x: T) - str: return a reveal_type(getattr_static(C[int], f)) # revealed: def f(self, x: int) - str reveal_type(getattr_static(C[int], f).__get__) # revealed: method-wrapper __get__ of function f reveal_type(getattr_static(C[int], f).__get__(None, C[int])) # revealed: def f(self, x: int) - str # revealed: bound method C[int].f(x: int) - str reveal_type(getattr_static(C[int], f).__get__(C[int](), C[int])) reveal_type(C[int].f) # revealed: def f(self, x: int) - str reveal_type(C[int]().f) # revealed: bound method C[int].f(x: int) - str bound_method C[int]().f reveal_type(bound_method.__self__) # revealed: C[int] reveal_type(bound_method.__func__) # revealed: def f(self, x: int) - str reveal_type(C[int]().f(1)) # revealed: str reveal_type(bound_method(1)) # revealed: str # error: [invalid-argument-type] Argument to function C.f is incorrect: Argument type Literal[1] does not satisfy upper bound C[int] of type variable Self C[int].f(1) # error: [missing-argument] reveal_type(C[int].f(C[int](), 1)) # revealed: str class DU: pass reveal_type(D[int]().f) # revealed: bound method D[int].f(x: int) - str这里有几个值得注意的实现细节C[int].f是未绑定方法def f(self, x: int) - strC[int]().f是绑定方法bound method C[int].f(x: int) - strgetattr_static系列调用验证了在不触发描述符协议的情况下特化信息依然保留C[int].f(1)同时触发两个诊断missing-argument缺self实参与invalid-argument-typeLiteral[1]不满足Self的上界C[int]这与Self类型变量有关子类DU特化为D[int]后继承的方法f正确显示为bound method D[int].f(x: int) - str。方法可以提及其他类型变量方法的泛型作用域A type variable used in a method that does not match any of the variables that parameterize the class makes this method a generic function in that variable.legacy 语法下方法签名里不属于类的类型变量会使该方法在该变量上成为泛型函数from typing import TypeVar, Generic T TypeVar(T) S TypeVar(S) class Legacy(Generic[T]): def m(self, x: T, y: S) - S: return y legacy: Legacy[int] Legacy[int]() reveal_type(legacy.m(1, string)) # revealed: Literal[string]关键点是方法签名中的类类型变量T不会绑定新的实例——它在类被特化时legacy: Legacy[int]已经被求解。仓库通过ty_extensions._internal.generic_context暴露了“泛型上下文”的内部表示来验证这一点from ty_extensions._internal import generic_context legacy.m(string, None) # error: [invalid-argument-type] reveal_type(legacy.m) # revealed: bound method Legacy[int].mS - S # revealed: ty_extensions._internal.GenericContext[TLegacy] reveal_type(generic_context(Legacy)) # revealed: ty_extensions._internal.GenericContext[Selfm, Sm] reveal_type(generic_context(legacy.m))generic_context(Legacy)显示类Legacy的泛型上下文只包含TLegacygeneric_context(legacy.m)则显示该绑定方法的上下文为Selfm, Sm——即只有方法自身引入的Self与S类类型变量T已通过特化被替换掉。PEP 695 语法下这一点更清晰——方法使用独立的类型变量class C[T]: def mS - S: return y c: C[int] C() reveal_type(c.m(1, string)) # revealed: Literal[string]未绑定类型变量不应出现在函数体与类体中Unbound type variables should not appear in the bodies of generic functions, or in the class bodies apart from method definitions.legacy 语法下from typing import TypeVar, Generic T TypeVar(T) S TypeVar(S) def f(x: T) - None: x: list[T] [] # error: [unbound-type-variable] y: list[S] [] class C(Generic[T]): # error: [unbound-type-variable] x: list[S] [] # This is not an error, as shown in the previous test def m(self, x: S) - S: return xf体内的x: list[T]合法T已绑定但y: list[S]中的S不属于f的泛型上下文报错类体属性x: list[S]同理但方法签名中的S合法——因为方法在S上是独立的泛型函数。PEP 695 语法行为一致只是定义“未绑定类型变量”时仍需借助 legacy 语法PEP 695 的类型变量不能出现在非泛型作用域中from typing import TypeVar S TypeVar(S) def fT - None: x: list[T] [] # error: [unbound-type-variable] y: list[S] [] class C[T]: # error: [unbound-type-variable] x: list[S] [] def m1(self, x: S) - S: return x def m2S - S: return x注意m1legacy 隐式泛型方法与m2[S]显式泛型方法都被允许前者是“方法可提及其他类型变量”规则的体现后者则用显式语法声明了独立的泛型上下文。未决问题Callable注解是否创建隐式泛型上下文typing 规范尚未解决、各类型检查器之间也存在分歧的一个场景是Callable[[T], T]这样的注解是否自动创建隐式泛型上下文ty的当前实现不对以下片段报错但作者明确注释“未来可能改变”from typing import TypeVar, Callable from ty_extensions._internal import generic_context T TypeVar(T) x: Callable[[T], T] lambda obj: obj # TODO: if we decide that Callable annotations always create an implicit generic context, # all of these revealed types and invalid-argument-type diagnostics are incorrect. # If we decide that they do not, we should emit unbound-type-variable on both the # declaration of x in the global scope and the parameter annotation of y. # # NOTE: all the reveal_types are inside a function here so that we test the behaviour # of the declared type (from the annotation) rather than the local inferred type def test(y: Callable[[T], T]): # revealed: None reveal_type(generic_context(x)) # revealed: (TypeVar, /) - TypeVar reveal_type(x) # error: [invalid-argument-type] # revealed: TypeVar reveal_type(x(42)) # revealed: None reveal_type(generic_context(y)) # revealed: (Ttest, /) - Ttest reveal_type(y) # error: [invalid-argument-type] # revealed: Ttest reveal_type(y(42))代码块内的TODO注释给出了两种可能走向如果Callable注解总是创建隐式泛型上下文那么上面的revealed类型与invalid-argument-type诊断全都是错误的反之则应同时为全局作用域x的声明和y的参数注解报unbound-type-variable。测试特意把reveal_type放进函数体是为了验证“注解声明的类型”而非局部推断类型。目前generic_context(x)与generic_context(y)都揭示为None说明实现暂不把Callable[[T], T]当作泛型上下文。嵌套正式类型变量必须互异shadowed-type-variable泛型函数与泛型类可以互相嵌套但同一个类型变量不能用于嵌套的泛型定义中。typing 规范只明确提到了两种具体形态A generic class definition that appears inside a generic function should not use type variables that parameterize the generic function.A generic class nested in another generic class cannot use the same type variables.仓库作者注明我们假设更一般的形式成立即嵌套泛型定义无论是函数还是类都不得使用外层绑定的类型变量。触发该规则的 lint 是SHADOWED_TYPE_VARIABLE在 crates/ty_python_semantic/src/types/diagnostic.rs 中声明stable0.0.20默认Level::Error语义文档见 crates/ty_python_semantic/resources/lint_docs/shadowed-type-variable.md。泛型函数嵌套泛型函数def fT - None: def okS - None: ... # error: [shadowed-type-variable] def badT - None: ...内层使用新类型变量S合法复用外层T则报错。泛型 TypeVarTuple 嵌套同样规则适用于可变长类型参数元组*Tsdef outer*Ts - None: def ok*Us - None: ... # snapshot: shadowed-type-variable def bad*Ts - None: ...文档内嵌的 snapshot 展示了实际诊断输出error[shadowed-type-variable]: Generic function bad uses TypeVarTuple Ts already bound by an enclosing scope -- src/mdtest_snippet.py:5:9 | 5 | def bad*Ts - None: ... | ^^^ Ts used in function definition here | ::: src/mdtest_snippet.py:1:5 | 1 | def outer*Ts - None: | ------------------------------ TypeVarTuple Ts is bound in this enclosing scope可以看到ty的诊断不仅指出违规位置还会用:::次级标注指出外层绑定该类型变量的作用域。泛型方法嵌套泛型类class C[T]: def okS - None: ... # error: [shadowed-type-variable] def badT - None: ...泛型类嵌套泛型函数from typing import Iterable def fT - None: class Ok[S]: ... # error: [shadowed-type-variable] class Bad1[T]: ... # error: [shadowed-type-variable] class Bad2(Iterable[T]): ...注意Bad2(Iterable[T])的基类列表里出现外层T同样是错误。泛型类嵌套泛型类from typing import Iterable class C[T]: class Ok1[S]: ... # error: [shadowed-type-variable] class Bad1[T]: ... # error: [shadowed-type-variable] class Bad2(Iterable[T]): ...例外基类恰好与外层类型参数同名一个微妙的边界情况嵌套泛型类继承的泛型基类恰好带有与外层作用域类型参数同名的类型参数时只要嵌套类只使用自己的类型参数就不应报错class Base[T]: pass class Outer[T]: class InnerU: pass这里Base[U]使用的是Inner自己的UBase的T与外层Outer的T只是恰好同名互不相关。但直接引用外层类型变量依然非法class Outer[T]: # error: [shadowed-type-variable] class Bad(list[T]): ...类基列表在类型参数作用域内求值类基列表的求值发生在该类的类型参数作用域之内。这意味着基类位置引用的名称可能被解析为类型变量在声明之后而不会引用到尚未定义的类名class C_T: ... # D in list[D] is resolved to be a type variable of class D. class DD: ... # error: [unresolved-reference] Name E used when not defined if E: class E_T: ... # error: [unresolved-reference] Name F used when not defined F # error: [unresolved-reference] Name F used when not defined class F_T: ... def foo(): class G_T: ... # error: [unresolved-reference] Name H used when not defined if H: class H_T: ...要点class C_T中基类C是在类定义完成前被引用的因此解析为未定义名称报unresolved-referenceclass DD是合法的基类列表中的D被解析为类D自己的类型变量它此时已经在类型参数作用域内绑定list[D]即list[DD]函数体内定义的嵌套类遵循相同规则G、H在定义完成前引用自身都报未定义名称。类作用域不覆盖内部作用域与普通符号一样泛型类的类型变量只在该类的作用域内可用不会泄漏到嵌套作用域class C[T]: ok1: list[T] [] class Bad: # error: [unbound-type-variable] bad: list[T] [] class Inner[S]: ... ok2: Inner[T]类体属性ok1: list[T]与ok2: Inner[T]合法但嵌套类Bad的属性使用外层T报unbound-type-variable。类型参数默认值不得引用外层作用域类型参数invalid-type-variable-default按 typing 规范类型参数的默认值不得引用外层作用域的类型参数。本节环境切换到python-version 3.13PEP 695 默认值语法在 3.13 才可用。类类型参数上越界的默认值已由invalid-generic-class诊断覆盖本节只覆盖PEP 695 函数/类型别名作用域以及legacyTypeVar用于函数/方法签名的剩余场景。对应 lint 在 crates/ty_python_semantic/src/types/diagnostic.rs 中声明stable0.0.16默认Level::Error。嵌套函数def outer[T](): # error: [invalid-type-variable-default] Type parameter U cannot use outer-scope type parameter T as its default def inner[U T](): ... def ok[U int](): ... # OKinner[U T]中U的默认值引用了外层outer的T报错U int合法。类中嵌套函数class C[T]: # error: [invalid-type-variable-default] def fU T: ... def gU int: ... # OK类中嵌套类型别名class C[T]: # error: [invalid-type-variable-default] type Alias[U T] list[U] type Ok[U int] list[U] # OKlegacy TypeVar 用于方法、外层有类类型变量from typing import TypeVar, Generic T1 TypeVar(T1) T2 TypeVar(T2, defaultT1) class Foo(Generic[T1]): # error: [invalid-type-variable-default] Invalid use of type variable T2: default of T2 refers to out-of-scope type variable T1 def method(self, x: T2) - T2: return xlegacy 类型变量T2的默认值引用了类Foo的类型变量T1同样被拒绝。legacy TypeVar 用于嵌套函数from typing import TypeVar, Generic T TypeVar(T) U TypeVar(U, defaultT) def outer(x: T) - T: # error: [invalid-type-variable-default] def inner(y: U) - U: return y return x默认值引用后声明的类型变量legacy 类型变量的默认值只能引用先声明的类型变量from typing import TypeVar, Generic T TypeVar(T, defaultint) U TypeVar(U, defaultT) # error: [invalid-type-variable-default] def bad(y: U, z: T) - tuple[U, T]: return y, z # OK, because the typevar with the default comes after the one without def fine(y: T, z: U) - tuple[U, T]: return z, ybad中U的默认值T出现在T的声明之前签名顺序y: U, z: T报错fine中T先声明、U后声明合法。legacy 类型变量顺序带默认值的不得排在不带默认值的前面from typing import TypeVar T1 TypeVar(T1, defaultint) T2 TypeVar(T2) T3 TypeVar(T3) DefaultStrT TypeVar(DefaultStrT, defaultstr) # error: [invalid-type-variable-default] def f(x: T1, y: T2) - tuple[T1, T2]: return x, y # error: [invalid-type-variable-default] def g(x: T2, y: T1, z: T3) - tuple[T2, T1, T3]: return x, y, z # error: [invalid-type-variable-default] def h(x: T1, y: T2, z: DefaultStrT, w: T3) - tuple[T1, T2, DefaultStrT, T3]: return x, y, z, w def ok(x: T2, y: T1) - tuple[T2, T1]: return x, y def ok2(x: T1, y: DefaultStrT) - tuple[T1, DefaultStrT]: return x, y规则是带默认值的类型变量必须排在无默认值类型变量的后面。okT2无默认值在前、T1有默认值在后与ok2T1、DefaultStrT均有默认值合法f、g、h均因出现“默认值变量排在无默认值变量之前”而报错——这也与 Python 函数参数中默认参数的排序约束一致。混合作用域类型参数方法可以同时拥有方法自身作用域的类型参数与外层类的类型参数两者在签名中共存。ty_extensions._internal.into_regular_callable用于把绑定方法转换成普通可调用对象以便揭示其完整签名from typing import Generic, TypeVar from ty_extensions._internal import into_regular_callable T TypeVar(T) S TypeVar(S) class Foo(Generic[T]): def bar(self, x: T, y: S) - tuple[T, S]: raise NotImplementedError def f(x: type[Foo[T]]) - T: # revealed: S - tuple[Tf, S] reveal_type(into_regular_callable(x.bar)) raise NotImplementedError揭示结果显示bar的T被绑定为函数f泛型上下文中的Tf因为x: type[Foo[T]]特化了Foo而S保持为bar方法自身的类型参数用[S]前缀标注——这正是一个“混合作用域”类型参数的完整形态。如何运行这些测试如果你希望亲手运行scoping.md中的用例可以借助 crates/ty_python_semantic/mdtest.py 提供的测试运行器。它支持按路径过滤例如# 在仓库根目录执行运行 generics 目录下的 scoping 测试 uv run crates/ty_python_semantic/mdtest.py generics/scoping.md该脚本的核心流程见MDTestRunner类为以cargo test --package ty_python_semantic --testmdtest编译测试先以human消息格式检查编译错误再以json格式定位 mdtest 可执行文件路径执行编译产物测试名形如mdtest::generics/scoping.md支持--exact精确匹配通过环境变量控制行为MDTEST_EXTERNAL是否启用外部依赖测试对应 CLI--enable-external、MDTEST_UPGRADE_LOCKFILES对应--no-lockfile-upgrades、MDTEST_UPDATE_SNAPSHOTS对应--no-snapshot-updates无参数运行时进入watch模式监听ty_python_semantic、ty_vendored、ty_test/src、mdtest/src等目录的变更Rust 源码或 vendored typeshed 变更后自动重编译并重跑测试.md变更则只重跑受影响的用例删除被拒绝的.snap.new快照文件也会触发对应用例重跑。scoping.md中同时使用了几种测试标注语法# error: [diagnostic-name]内联断言、# revealed: ...的reveal_type期望输出、!-- snapshot-diagnostics --触发的诊断快照以及内嵌snapshot代码块如 TypeVarTuple 遮蔽一节所示。每段代码块对应一个独立测试因此这份 Markdown 文档本身就是ty泛型作用域行为的可执行规范。总结从规范到实现的作用域规则全景回顾全文ty对类型变量作用域的处理可以归纳为以下几条核心原则绑定即合法类型变量只能在绑定它的泛型函数/类或其方法、基类列表、类型别名赋值中使用否则报unbound-type-variable特化即固定类类型变量由接收者特化后不再重新推断向object、bound 父类或约束的任意特化赋值都不改变其绑定TClass符号保持不变诊断等级默认Error见 diagnostic.rs嵌套即隔离嵌套泛型定义必须使用新的类型变量复用外层变量报shadowed-type-variable但基类“恰好同名”的参数不受牵连见 shadowed-type-variable.md默认值受序约束类型参数默认值不得引用外层作用域或后声明的类型变量带默认值的变量不得排在不带默认值的变量之前违者报invalid-type-variable-default见 invalid-type-variable-default.md场景求值有序类基列表在类型参数作用域内求值、类作用域不覆盖内部作用域、Callable注解的隐式泛型上下文问题仍为未决事项。这些规则在ty_python_semanticcrate 的类型推断与诊断系统中src/types/、src/types/generics.rs有完整的实现支撑而 scoping.md 则以可执行测试的形式把它们固化下来——既是一份规范文档也是ty泛型检查行为最权威的参考。【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价