charon_driver/translate/
resolve_path.rs1use std::sync::Arc;
3
4use crate::hax;
5use crate::hax::{BaseState, SInto};
6use anyhow::bail;
7use charon_lib::name_matcher::NamePattern;
8use itertools::Itertools;
9use rustc_ast::Mutability;
10use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
11use rustc_middle::ty::{self, FloatTy, IntTy, TyCtxt, UintTy, fast_reject::SimplifiedType};
12use rustc_span::symbol::Symbol;
13
14fn find_primitive_impls<'tcx>(
15 tcx: TyCtxt<'tcx>,
16 name: &str,
17) -> impl Iterator<Item = DefId> + use<'tcx> {
18 let ty = match name {
19 "bool" => SimplifiedType::Bool,
20 "char" => SimplifiedType::Char,
21 "str" => SimplifiedType::Str,
22 "array" => SimplifiedType::Array,
23 "slice" => SimplifiedType::Slice,
24 "const_ptr" => SimplifiedType::Ptr(Mutability::Not),
28 "mut_ptr" => SimplifiedType::Ptr(Mutability::Mut),
29 "isize" => SimplifiedType::Int(IntTy::Isize),
30 "i8" => SimplifiedType::Int(IntTy::I8),
31 "i16" => SimplifiedType::Int(IntTy::I16),
32 "i32" => SimplifiedType::Int(IntTy::I32),
33 "i64" => SimplifiedType::Int(IntTy::I64),
34 "i128" => SimplifiedType::Int(IntTy::I128),
35 "usize" => SimplifiedType::Uint(UintTy::Usize),
36 "u8" => SimplifiedType::Uint(UintTy::U8),
37 "u16" => SimplifiedType::Uint(UintTy::U16),
38 "u32" => SimplifiedType::Uint(UintTy::U32),
39 "u64" => SimplifiedType::Uint(UintTy::U64),
40 "u128" => SimplifiedType::Uint(UintTy::U128),
41 "f16" => SimplifiedType::Float(FloatTy::F16),
42 "f32" => SimplifiedType::Float(FloatTy::F32),
43 "f64" => SimplifiedType::Float(FloatTy::F64),
44 "f128" => SimplifiedType::Float(FloatTy::F128),
45 _ => {
46 return [].iter().copied();
47 }
48 };
49 tcx.incoherent_impls(ty).iter().copied()
50}
51
52pub fn def_path_def_ids<'a, 'tcx>(
65 s: &impl BaseState<'tcx>,
66 pat: &'a NamePattern,
67 strict: bool,
68) -> anyhow::Result<Vec<DefId>> {
69 use charon_lib::name_matcher::{PatElem, PatTy};
70 let tcx = s.base().tcx;
71 let mut items: Vec<DefId> = vec![];
72 for (i, elem) in pat.elems.iter().enumerate() {
73 if i == 0 {
74 match elem {
75 PatElem::Ident { name: elem, .. } => {
76 let segment = Symbol::intern(elem);
77 items = tcx
78 .crates(())
79 .iter()
80 .copied()
81 .chain([LOCAL_CRATE])
82 .filter(move |&num| {
84 tcx.crate_name(num) == segment
85 || (num == LOCAL_CRATE && elem == "crate")
86 })
87 .map(CrateNum::as_def_id)
88 .collect_vec();
89 items.extend(find_primitive_impls(tcx, elem));
90 }
91 PatElem::Glob => {
92 items = tcx
93 .crates(())
94 .iter()
95 .copied()
96 .chain([LOCAL_CRATE])
97 .map(CrateNum::as_def_id)
98 .collect_vec();
99 }
100 PatElem::Impl(impl_pat) => match impl_pat.elems.as_slice() {
101 [
102 ..,
103 PatElem::Ident {
104 generics,
105 is_trait: true,
106 ..
107 },
108 ] => match generics.as_slice() {
109 [] => bail!("malformed trait impl pattern"),
110 [PatTy::Pat(self_pat)] => {
111 let impls = def_path_def_ids(s, impl_pat, strict)?
112 .into_iter()
113 .flat_map(|trait_def_id| tcx.all_impls(trait_def_id));
114 match self_pat.elems.as_slice() {
115 [PatElem::Glob] => {
116 items = impls.collect_vec();
117 }
118 _ => {
119 let self_ty_def_ids = def_path_def_ids(s, self_pat, strict)?;
120 items = impls
121 .filter(|impl_def_id| {
122 let impl_self_ty = tcx
123 .impl_trait_ref(impl_def_id)
124 .skip_binder()
125 .self_ty();
126 if let ty::Adt(adt_def, _) = impl_self_ty.kind() {
127 self_ty_def_ids.contains(&adt_def.did())
128 } else {
129 false
130 }
131 })
132 .collect_vec();
133 }
134 }
135 }
136 [_] => bail!("`--start-from` only supports implementations on named types"),
137 [_, _, ..] => bail!("`--start-from` does not support trait generics"),
138 },
139 [
140 ..,
141 PatElem::Ident {
142 is_trait: false, ..
143 },
144 ] => bail!("`--start-from` does not support inherent impls"),
145 _ => bail!("`--start-from` does not support this impl pattern"),
146 },
147 }
148 } else {
149 let nameable_children = items.iter().copied().flat_map(|def_id| {
150 let hax_def: Arc<hax::FullDef> = def_id.sinto(s).full_def(s);
151 hax_def.nameable_children(s)
152 });
153 match elem {
154 PatElem::Ident { name: elem, .. } => {
155 items = nameable_children
156 .filter(|(child_name, _)| child_name.as_str() == elem)
157 .filter_map(|(_, def_id)| def_id.as_rust_def_id())
158 .collect();
159 }
160 PatElem::Glob => {
161 items = nameable_children
162 .filter_map(|(_, def_id)| def_id.as_rust_def_id())
163 .collect();
164 }
165 PatElem::Impl(_) => bail!(
166 "`--start-from` only supports impl patterns if they're the first element of the path"
167 ),
168 }
169 }
170 if strict && items.is_empty() {
171 let prefix = NamePattern {
172 elems: pat.elems[..=i].to_vec(),
173 };
174 if i == 0 {
175 bail!(
176 "path `{prefix}` does not correspond to any item; did you mean `crate::{prefix}`?"
177 )
178 } else {
179 bail!("path `{prefix}` does not correspond to any item")
180 }
181 }
182 }
183 Ok(items)
184}