本文档描述了 Swift 的名称查找和作用域系统,该系统决定了标识符在代码中的解析方式。它涵盖了编译器如何在不同上下文中查找变量、函数和类型名称,并解释了决定名称可见性的作用域层次结构。有关名称查找后的类型检查等相关主题,请参阅 类型系统。
名称查找是解析 Swift 源代码中标识符到声明的过程。查找过程会遍历作用域的层次结构,每个作用域对应于程序中的一个语法结构,以查找与给定名称匹配的声明。
名称查找的主要入口点是 ASTScopeImpl::unqualifiedLookup(),它接收一个源文件、一个源位置和一个用于收集找到的声明的消费者。
来源: lib/AST/ASTScopeLookup.cpp41-47 lib/AST/UnqualifiedLookup.cpp238-273
Swift 编译器通过一系列 ASTScopeImpl 对象的层次结构来表示词法作用域。每个作用域都对应于源代码中声明可能可见的一个区域。
作用域树是惰性构建的——编译器仅构建当前操作所需的树的部分。这由 expandAndBeCurrent() 方法管理,该方法按需构建子作用域。
来源: include/swift/AST/ASTScope.h109-132 lib/AST/ASTScopeCreation.cpp47-237
ASTScope 树中的每个作用域都有一个源范围,用于定义其在源代码中的范围。作用域的排列方式是:
源范围管理由 checkSourceRangeBeforeAddingChild() 强制执行,该函数在向树中添加新作用域时会验证这些约束。
来源: lib/AST/ASTScopeSourceRange.cpp42-103
非限定名称查找发生在解析没有限定符的标识符时(例如,仅 identifier 而不是 some.identifier)。此过程包含几个阶段:
查找过程由 UnqualifiedLookupFlags 中定义的各种标志控制。
| 标志 | 目的 |
|---|---|
| TypeLookup | 仅查找类型 |
| AllowProtocolMembers | 考虑协议成员 |
| IgnoreAccessControl | 忽略访问级别限制 |
| IncludeOuterResults | 包含来自外部作用域的结果 |
| MacroLookup | 仅查找宏 |
| ModuleLookup | 仅查找模块 |
来源: lib/AST/UnqualifiedLookup.cpp237-296 include/swift/AST/NameLookup.h231-260
名称查找操作的结果由 LookupResult 和 LookupResultEntry 类表示。
LookupResultEntry 包含一个找到的声明、其基础声明上下文以及基础声明(这对实例成员很重要)。LookupResult 包含一个条目集合,分为“内部”和“外部”结果,用于处理作用域可见性。名称遮蔽发生在内部作用域的声明与外部作用域的声明同名时。查找系统通过优先考虑内部作用域中的声明,以及将结果组织成“内部”和“外部”类别来处理这种情况。
来源: include/swift/AST/NameLookup.h53-229 lib/AST/NameLookup.cpp310-363
泛型参数在其声明的作用域及其子作用域中可见。ASTScope 系统确保泛型参数可以在以下位置正确查找:
例如,在泛型函数中,参数在函数体内是可见的。
来源: lib/AST/ASTScopeLookup.cpp185-201
闭包表达式会创建自己的作用域,并有捕获外部作用域变量的特殊规则。闭包参数创建自己的作用域,然后是闭包体。
闭包可以访问:
查找系统处理各种捕获场景,包括 weak self 和其他修改引用的捕获。
来源: lib/AST/ASTScopeCreation.cpp98-195 lib/AST/UnqualifiedLookup.cpp354-441
模式绑定声明(用于 let 和 var 声明)会创建特殊的作用域规则。在模式中声明的变量在其自己的初始化器中不可见,以防止类似以下的代码:
这由 PatternEntryInitializerScope 处理,该作用域在执行查找时会跳过父模式绑定作用域。
来源: lib/AST/ASTScopeLookup.cpp318-357
可以使用几种工具来可视化和调试 ASTScope 树:
-dump-scope-maps,它会打印整个作用域树。ASTScopeImpl::print() 方法,它可以打印一个作用域及其子作用域。dumpOneScopeMapLocation() 方法,它会查找并打印特定源位置的作用域。这些工具对于理解编译器如何为给定的代码段构建作用域层次结构非常有价值。
来源: lib/AST/ASTScopePrinting.cpp41-68
为了说明名称查找和作用域的实际工作原理,请考虑以下 Swift 代码示例:
在 nestedFunc 中查找 staticVar 时,编译器会:
NestedFuncBody 作用域开始。staticVar,因此移动到 NestedFuncDecl 作用域。MethodBody。MethodDecl。StructInner。StructInner 作用域中找到了 staticVar 并停止。这演示了基于作用域的查找的层次结构性质以及它如何在嵌套上下文中解析标识符。
来源: test/expr/closure/closures.swift134-148
名称查找是类型检查的关键前置步骤。在名称解析为声明后,类型检查器可以确定:
查找系统提供了关于声明的必要信息,以启用这些后续的类型检查操作。
来源: lib/Sema/TypeCheckNameLookup.cpp73-91
Swift 的名称查找和作用域系统通过一个强大的框架为各种上下文中的标识符解析提供了支持。通过将源代码组织到作用域层次结构中并系统地搜索该层次结构,编译器可以提供准确且可预测的名称解析,这对于闭包、泛型和访问控制等语言特性的正确工作至关重要。
刷新此 Wiki
最后索引时间2025 年 4 月 18 日 (721944)