菜单

协议一致性检查

相关源文件

此页面介绍了 Swift 的协议一致性检查系统,该系统可验证给定类型是否正确地符合协议。一致性检查器会分析值和类型见证,匹配函数签名,并执行关联类型推断,以确保类型满足所有协议要求。

有关基于约束的类型检查系统的信息,请参阅基于约束的类型检查。有关 Swift 并发类型检查的详细信息,请参阅并发类型检查

协议一致性概述

协议一致性检查是 Swift 类型系统的一个关键组成部分,可确保面向协议编程的静态类型安全。当一个类型声明符合某个协议时,编译器会验证:

  1. 该类型为所有必需的协议成员提供了实现(见证)。
  2. 这些实现满足协议的签名要求。
  3. 关联类型满足其约束和要求。
  4. 关联类型的任何必需协议一致性都已满足。

来源:lib/Sema/TypeCheckProtocol.cpp1-16 lib/Sema/TypeCheckProtocol.h98-108

一致性检查架构

协议一致性检查系统包含几个相互关联的组件。

来源:lib/Sema/TypeCheckProtocol.h30-127 lib/Sema/TypeCheckProtocol.h109-175

关键组件

  1. WitnessChecker:基类,提供将见证匹配到要求的功能。

  2. ConformanceChecker:管理整体一致性检查过程,包括查找和验证见证。

  3. RequirementMatch:表示将见证匹配到要求的結果,包括成功或具体的失败原因。

  4. AssociatedTypeInference:处理关联类型见证的推断,当它们没有被明确提供时。

见证匹配过程

见证匹配是确定符合类型中的声明是否满足协议要求的过程。这主要在 matchWitness 函数中实现。

结构匹配

在详细类型检查之前,系统会执行结构匹配以确保基本兼容性。

  • 对于方法:检查静态/非静态、可变/不可变、throws/rethrows 等。
  • 对于属性:检查 get/set 可用性、可变行为等。
  • 对于下标:检查参数计数、可变行为等。

来源:lib/Sema/TypeCheckProtocol.cpp512-691

类型匹配

结构匹配后,类型检查确保参数和返回类型兼容。

  1. 对于函数,会检查每个参数类型和返回类型。
  2. 进行类型调整以处理方差(协变返回类型、逆变参数类型)。
  3. 可选调整处理要求和见证之间可选性的差异。
  4. 对逃逸与非逃逸函数以及 Sendable 类型进行特殊处理。

来源:lib/Sema/TypeCheckProtocol.cpp702-936

关联类型推断

当协议定义关联类型时,符合类型的类型必须显式声明类型见证,或者由编译器推断。

类型见证解析过程

来源:lib/Sema/AssociatedTypeInference.cpp442-637 lib/Sema/AssociatedTypeInference.cpp1065-1211

推断策略

关联类型推断系统使用多种策略来确定类型见证。

  1. 显式声明:在符合类型中查找同名类型。
  2. 值见证分析:检查函数签名中的类型以推断关联类型。
  3. 默认定义:使用协议的默认类型定义。
  4. 相同类型要求:应用协议中的相同类型约束。
  5. 泛型参数绑定:对于简单情况,使用同名泛型参数。

当多种策略建议不同见证时,系统会尝试找到最佳解决方案或报告歧义。

来源:lib/Sema/AssociatedTypeInference.cpp1064-1107 lib/Sema/AssociatedTypeInference.cpp244-421

类型见证检查

一旦确定了潜在的类型见证(通过显式声明或推断),就必须根据关联类型的要求对其进行验证。

来源:lib/Sema/AssociatedTypeInference.cpp147-217

要求匹配

将要求与见证匹配的结果封装在 RequirementMatch 对象中,该对象描述了匹配是否成功以及原因。

匹配类型分类

匹配类型描述
精确见证与要求完全匹配。
类型冲突声明类型不匹配(例如,方法与属性)。
类型冲突要求和见证之间的类型不匹配。
变异冲突变异/非变异不匹配。
Throws 冲突Throws 行为不匹配。
Async 冲突Async 行为不匹配。
Rethrows 冲突Rethrows 行为不匹配。
缺少要求见证不满足要求。
见证无效见证声明无效。
可设置冲突属性可设置性不匹配。

来源:lib/Sema/TypeCheckProtocol.cpp175-199 lib/Sema/TypeCheckProtocol.cpp514-681

特殊情况和处理

协议一致性检查包含对各种边缘情况的特殊处理。

Objective-C 互操作性

在符合 Objective-C 协议或使用 Objective-C 方法作为见证时,系统会:

  • 检查选择器名称是否匹配。
  • 处理可空性差异。
  • 管理隐式展开的可选类型转换。

来源:lib/Sema/TypeCheckProtocol.cpp204-247 lib/Sema/TypeCheckProtocol.cpp100-202

可微分编程支持

对于带有 @differentiable 属性的协议,一致性检查器会:

  • 确保见证具有可兼容的可微分属性。
  • 可能合成隐式可微分属性。
  • 检查导数配置是否符合协议要求。

来源:lib/Sema/TypeCheckProtocol.cpp310-489

Actor 隔离和并发

协议一致性检查可验证要求和见证之间的适当 Actor 隔离。

  • 确保 async/sync 兼容性。
  • 在需要时检查 Sendable 类型。
  • 验证 Throws 行为的兼容性。

来源:lib/Sema/TypeCheckProtocol.cpp834-847 lib/Sema/TypeCheckProtocol.cpp875-884

一致性检查工作流程

协议一致性检查的总体工作流程遵循以下步骤:

来源:lib/Sema/TypeCheckProtocol.h145-157 lib/Sema/TypeCheckProtocol.cpp1015-1085 lib/Sema/AssociatedTypeInference.cpp1209-1211

示例:AsyncSequence 一致性

Swift 标准库广泛使用了协议一致性和关联类型推断。 AsyncSequence 协议提供了一个很好的例子,说明了关联类型推断如何与相关协议协同工作。

当一个类型符合 AsyncSequence 时,一致性检查系统会:

  1. 查找 makeAsyncIterator() 的见证。
  2. 确定其返回类型是 Iterator 关联类型的见证。
  3. 推断 Element 必须与迭代器的元素类型相同。
  4. 对于 Failure 类型,要么使用显式见证,要么从迭代器的失败类型推断。

测试文件 async_sequence_conformance.swift 演示了此推断机制。

来源: test/ModuleInterface/async_sequence_conformance.swift7-69 lib/Sema/AssociatedTypeInference.cpp420-440

常见挑战和错误案例

协议一致性检查可能遇到几个常见问题。

缺少见证

当类型未为协议要求提供实现时,系统会报告一个缺失见证的错误。

类型见证歧义

当多个潜在的类型见证可以满足关联类型的要求时,系统会报告一个歧义。

类型见证冲突

当类型推断为同一关联类型产生冲突的类型见证时,系统必须解决该冲突或报告一个错误。

无效类型见证

当建议的类型见证未能满足关联类型的约束(协议一致性、超类要求等)时,系统会报告一个关于哪个约束未被满足的特定错误。

来源: lib/Sema/AssociatedTypeInference.cpp584-602 lib/Sema/AssociatedTypeInference.cpp602-635

结论

协议一致性检查是一个复杂的系统,可确保 Swift 协议导向设计中的类型安全。通过结合显式见证验证和强大的类型推断能力,它在灵活性和编译时安全性保证之间取得了平衡。该系统与 Swift 类型检查器的其他部分紧密协作,以验证声明的一致性是否满足所有协议要求,并在不满足时生成全面的诊断信息。