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