Swift 5.2 新诊断框架

Swift 5.2 引入了新的诊断框架,改善了编译器的错误提示,使其更准确地定位问题。该框架利用约束修复技术处理类型推断中的不一致,提供定制化的错误诊断和修复建议。博客详细介绍了新框架的工作原理,通过示例展示了类型推断、约束系统以及如何改进错误诊断,如参数类型不匹配、缺失成员等问题。
摘要由CSDN通过智能技术生成

本文由知乎网友“漫慢忙”翻译自官方博客 《New Diagnostic Architecture Overview》

诊断程序(Diagnostics)在编程语言体验中扮演着非常重要的角色。开发人员在编写代码时非常关心的一点是:编译器可以在任何情况下(尤其是代码不完整或无效时)提供适当的指导并指出问题。

在此博客文章中,我们想分享一些即将推出的 Swift 5.2 的重要更新,以改进新版本的的诊断功能。这包括编译器诊断故障的新策略,该策略最初是 Swift 5.1 发行版的一部分,其引入了一些令人兴奋的新结果并改进了错误消息。

挑战

Swift 是一种具有丰富表现力的语言,它有丰富的类型系统,这个系统有许多特性,例如类继承,协议一致性,泛型和重载。尽管作为程序员,我们会竭尽全力编写格式良好的代码,但有时我们需要一点帮助。幸运的是,编译器知道什么样的 Swift 代码是有效的或者无效的。问题是如何更好地告诉您出了什么问题,问题在哪以及如何解决。

编译器做了许多事情来确保程序的正确性,但是这项工作的重点一直是改进类型检查器。Swift 类型检查器强制执行有关如何在源代码中使用类型的规则,并在你违反了这些规则时告诉你。

例如以下代码:

struct S<T> {
  init(_: [T]) {}
}

var i = 42
_ = S<Int>([i!])
复制代码

会产生以下诊断结果:

error: type of expression is ambiguous without more context
复制代码

尽管这个诊断结果指出了真正的错误,但由于它不明确,因此并没有太大的帮助。这是因为旧的类型检查器主要用来猜测错误的确切位置。这在许多情况下都有效,但是用户仍然会出现很多无法准确识别的编程错误。为了解决这个问题,我们正在开发一种新的诊断架构。类型检查器不再是在猜测错误发生的位置,而是尝试在遇到问题时“修复”问题,并记住所应用的修复措施。这不仅使类型检查器可以查明更多种类的程序中的错误,也使它能够提前暴露更多的故障。

类型推断概述

由于新的诊断框架与类型检查器紧密结合,因此我们需要先讨论一下类型推断。请注意,这里只是简单地介绍一下。有关类型检查更多详细信息,请参阅 compiler’s documentation on the type checker[1]

Swift 使用基于约束的类型检查器实现双向类型推断,这使人联想到经典的 Hindley-Milner[2] 类型推断算法[3]

• 类型检查器将源代码转换为约束系统,该约束系统表示代码中类型之间的关系。

• 类型关系是通过类型约束表达的,类型约束要么对单个类型提出要求(例如,它是整数字面量类型),要么将两种类型相关联(例如,一种类型可以转换为另一种类型)。

• 约束中描述的类型可以是 Swift 类型系统中的任何类型,包括元组类型、函数类型、枚举/结构/类类型、协议类型和泛型类型。此外,类型可以是表示为 $<name> 的类型变量。

• 类型变量可以在任何其他类型中使用,例如,类型变量 $Foo 在元组类型 ($Foo,Int) 中使用。

约束系统执行三步操作:

• 产生约束

• 求解约束

• 应用解决方案

诊断过程关注的阶段是约束生成和求解。

给定输入表达式(有时还包括其他上下文信息),约束求解器将生成以下信息:

• 一组类型变量,代表每个子表达式的抽象类型

• 一组描述这些类型变量之间关系的类型约束

最常见的约束类型是二进制约束(binary constraint),它涉及两种类型,可以表示为:

type1 <constraint kind> type2
复制代码

常用的二进制约束有:

$X <bind to> Y - 将类型变量 $X 绑定到固定类型 Y

X <convertible to> Y - 转换约束要求第一个类型 X 可转换为第二个 Y,其中包括子类型和等价形式

X <conforms to> Y - 指定第一种类型 X 必须符合协议 Y

(Arg1,Arg2,...) → Result <applicable to> $Function - “适用函数(applicable function)”约束要求两种类型都是具有相同输入和输出类型的函数类型

约束生成完成后,求解程序将尝试为约束系统中的每个类型变量分配具体类型,并生成满足所有约束的解决方案。

让我们来看看下面的例子:

func foo(_ str: String) {
  str + 1
}
复制代码

对于我们来说,很快就能发现表达式 str + 1 存在问题以及该问题所在的位置,但是类型推断引擎只能依靠约束简化算法来确定问题所在。

正如我们之前讨论的,约束求解器首先为 str1+ 生成约束。输入表达式的每个不同子元素(如str)均由以下方式表示:

• 具体类型(提前知道)

• 用 $<name> 表示的类型变量,可以假定满足与之关联的约束的任何类型。

约束生成阶段完成后,表达式 str + 1 的约束系统将具有类型变量和约束的组合。接下来让我们来看一下。

类型变量

$Str 表示变量 str 的类型,它是 + 调用中的第一个参数

$One 代表文字 1 的类型,它是 + 调用中的第二个参数

$Result 表示对运算符 + 调用的结果类型

$Plus 代表运算符 + 本身的类型,它是一组重载方法的集合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值