如何从 ra_ap_hir::Type 区分 *mut 与 *const 裸指针?
结论
根据问题给出的 0.0.318 接口与源码,Type 的公开接口存在缺口:内部保存了裸指针的 Mutability,但列出的接口没有将其返回给调用方。remove_raw_ptr()、as_reference() 和 attach_db 都无法获取这个信息。
这一限制与版本有关:已核对的 ra_ap_hir 0.0.358 文档公开了 is_mutable_raw_ptr() 和 as_raw_ptr(),可以考虑升级到包含这些方法的版本。如果必须保留 0.0.318,则需要修改依赖源码,或继续使用显示字符串作为临时兜底。这两个方法最早加入的版本尚不确定。Type 接口文档
支持新接口时,直接读取类型信息
在已提供上述方法的版本中,如果只需要判断是否为 *mut T,可以这样写:
fn is_mutable_raw_ptr(ty: &ra_ap_hir::Type<'_>) -> bool {
ty.is_mutable_raw_ptr()
}
如果还需要指向的类型和可变性,可以使用:
if let Some((pointee, mutability)) = ty.as_raw_ptr() {
// 在这里使用 pointee 和 mutability。
}
as_raw_ptr() 返回 None 表示当前类型不是裸指针。对于需要分别处理非裸指针、*const T 和 *mut T 的分析逻辑,它比单个布尔值更合适。升级时还需检查其他 ra_ap_* 依赖的兼容性,不能只替换方法调用。
必须使用 0.0.318 时,在依赖内部补接口
根据问题提供的 TyKind 表示,如果只需要布尔判断,可以在 ra_ap_hir 源码现有的 impl<'db> Type<'db> 中添加:
pub fn is_mutable_raw_ptr(&self) -> bool {
matches!(
self.ty.kind(),
TyKind::RawPtr(_, hir_ty::next_solver::Mutability::Mut)
)
}
这段代码沿用题中 is_mutable_reference() 对内部 Mutability 的访问方式,需要放在能够访问 self.ty 的依赖源码中,不能直接放进应用 crate。
在应用里定义扩展 trait 也无法绕过字段可见性,为外部类型新增固有方法同样不可行。可通过 fork 或本地补丁维护这个改动,并将其提交上游。
如果要补充 as_raw_ptr(),应参照同版本 as_reference() 的实现,同时返回 self.derived(ty) 和可变性。还要沿用该版本内部 Mutability 到公开 Mutability 的转换方式,不能因为名称相同就假定二者是同一个类型。
为什么现有尝试拿不到可变性
remove_raw_ptr()只返回指向的类型,丢弃了外层指针的可变性。例如,*mut i32和*const i32都会得到i32。as_reference()匹配引用类型;裸指针对应另一种TyKind变体。attach_db提供数据库上下文,不会改变 Rust 的字段访问权限。Type::walk()的回调接收Type,不会因此获得其私有内部表示。
显示字符串只能作为临时兜底
无法升级或修改依赖时,可以保留字符串方案,但建议明确处理“格式无法识别”的情况:
let raw_ptr_mutability: Option<bool> = if !ty.is_raw_ptr() {
None
} else {
let rendered = ty.display(db, display_target).to_string();
if rendered.starts_with("*mut ") {
Some(true)
} else if rendered.starts_with("*const ") {
Some(false)
} else {
None
}
};
这里的 None 合并了“不是裸指针”和“显示格式未识别”两种情况。如果后续逻辑需要区分,应改用自定义枚举。不要把所有不匹配 *mut 的结果都当成 *const T。
显示输出用于类型展示,不应自行假定它是稳定的机器读取协议。兜底逻辑应固定依赖版本,并检查 *mut T、*const T、嵌套裸指针和类型别名等情况。判断嵌套类型时,还应明确需要的是最外层指针的可变性,还是逐层分析。
备注:内容仅供参考。
