Skip to content

Commit c427482

Browse files
committed
1 parent 05b95ba commit c427482

File tree

4 files changed

+109
-291
lines changed

4 files changed

+109
-291
lines changed

support/crown/src/common.rs

Lines changed: 71 additions & 258 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,17 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
44

5-
use rustc_ast::Mutability;
6-
use rustc_hir::def::{DefKind, Res};
7-
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
8-
use rustc_hir::{ImplItemRef, ItemKind, Node, OwnerId, PrimTy, TraitItemRef};
5+
use rustc_hir::def::DefKind;
6+
use rustc_hir::def_id::{CrateNum, DefId};
97
use rustc_infer::infer::TyCtxtInferExt;
8+
use rustc_infer::traits::{EvaluationResult, Obligation, ObligationCause};
109
use rustc_lint::LateContext;
11-
use rustc_middle::ty::fast_reject::SimplifiedType;
12-
use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeVisitableExt, TypingEnv};
10+
use rustc_middle::ty::{self, GenericArg, TraitRef, Ty, TyCtxt, TypeVisitableExt};
1311
use rustc_span::hygiene::{ExpnKind, MacroKind};
14-
use rustc_span::symbol::{Ident, Symbol};
12+
use rustc_span::symbol::Symbol;
1513
use rustc_span::{Span, DUMMY_SP};
16-
use rustc_trait_selection::infer::InferCtxtExt;
17-
use rustc_type_ir::{FloatTy, IntTy, UintTy};
14+
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
15+
use rustc_type_ir::Upcast as _;
1816

1917
/// check if a DefId's path matches the given absolute type path
2018
/// usage e.g. with
@@ -65,286 +63,101 @@ macro_rules! symbols {
6563
}
6664
}
6765

68-
/*
69-
Stuff copied from clippy:
70-
*/
71-
72-
// This is adapted from
73-
// https://github.com/rust-lang/rust-clippy/blob/546408be416f0355a39601c1457b37727bc74395/clippy_utils/src/lib.rs#L517.
74-
fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
75-
let ty = match name {
76-
"bool" => SimplifiedType::Bool,
77-
"char" => SimplifiedType::Char,
78-
"str" => SimplifiedType::Str,
79-
"array" => SimplifiedType::Array,
80-
"slice" => SimplifiedType::Slice,
81-
// FIXME: rustdoc documents these two using just `pointer`.
82-
//
83-
// Maybe this is something we should do here too.
84-
"const_ptr" => SimplifiedType::Ptr(Mutability::Not),
85-
"mut_ptr" => SimplifiedType::Ptr(Mutability::Mut),
86-
"isize" => SimplifiedType::Int(IntTy::Isize),
87-
"i8" => SimplifiedType::Int(IntTy::I8),
88-
"i16" => SimplifiedType::Int(IntTy::I16),
89-
"i32" => SimplifiedType::Int(IntTy::I32),
90-
"i64" => SimplifiedType::Int(IntTy::I64),
91-
"i128" => SimplifiedType::Int(IntTy::I128),
92-
"usize" => SimplifiedType::Uint(UintTy::Usize),
93-
"u8" => SimplifiedType::Uint(UintTy::U8),
94-
"u16" => SimplifiedType::Uint(UintTy::U16),
95-
"u32" => SimplifiedType::Uint(UintTy::U32),
96-
"u64" => SimplifiedType::Uint(UintTy::U64),
97-
"u128" => SimplifiedType::Uint(UintTy::U128),
98-
"f32" => SimplifiedType::Float(FloatTy::F32),
99-
"f64" => SimplifiedType::Float(FloatTy::F64),
100-
#[allow(trivial_casts)]
101-
_ => {
102-
return [].iter().copied();
103-
},
104-
};
105-
106-
tcx.incoherent_impls(ty).iter().copied()
107-
}
108-
109-
fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
110-
match tcx.def_kind(def_id) {
111-
DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
112-
.module_children(def_id)
113-
.iter()
114-
.filter(|item| item.ident.name == name)
115-
.map(|child| child.res.expect_non_local())
116-
.collect(),
117-
DefKind::Impl { .. } => tcx
118-
.associated_item_def_ids(def_id)
119-
.iter()
120-
.copied()
121-
.filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name)
122-
.map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id))
123-
.collect(),
124-
_ => Vec::new(),
125-
}
126-
}
127-
128-
// This is adapted from clippy:
129-
// https://github.com/rust-lang/rust-clippy/blob/546408be416f0355a39601c1457b37727bc74395/clippy_utils/src/lib.rs#L574.
130-
fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
131-
let hir = tcx.hir();
132-
133-
let root_mod;
134-
let item_kind = match tcx.hir_node_by_def_id(local_id) {
135-
Node::Crate(r#mod) => {
136-
root_mod = ItemKind::Mod(r#mod);
137-
&root_mod
138-
},
139-
Node::Item(item) => &item.kind,
140-
_ => return Vec::new(),
141-
};
142-
143-
let res = |ident: Ident, owner_id: OwnerId| {
144-
if ident.name == name {
145-
let def_id = owner_id.to_def_id();
146-
Some(Res::Def(tcx.def_kind(def_id), def_id))
147-
} else {
148-
None
149-
}
150-
};
151-
152-
match item_kind {
153-
ItemKind::Mod(r#mod) => r#mod
154-
.item_ids
155-
.iter()
156-
.filter_map(|&item_id| res(hir.item(item_id).ident, item_id.owner_id))
157-
.collect(),
158-
ItemKind::Impl(r#impl) => r#impl
159-
.items
160-
.iter()
161-
.filter_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id))
162-
.collect(),
163-
ItemKind::Trait(.., trait_item_refs) => trait_item_refs
164-
.iter()
165-
.filter_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id))
166-
.collect(),
167-
_ => Vec::new(),
168-
}
169-
}
170-
171-
fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
172-
if let Some(local_id) = def_id.as_local() {
173-
local_item_children_by_name(tcx, local_id, name)
174-
} else {
175-
non_local_item_children_by_name(tcx, def_id, name)
176-
}
177-
}
178-
179-
/// Resolves a def path like `std::vec::Vec`.
180-
///
181-
/// Can return multiple resolutions when there are multiple versions of the same crate, e.g.
182-
/// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0.
183-
///
184-
/// Also returns multiple results when there are multiple paths under the same name e.g. `std::vec`
185-
/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
186-
///
187-
/// This function is expensive and should be used sparingly.
188-
pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> {
189-
fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator<Item = DefId> + '_ {
190-
tcx.crates(())
191-
.iter()
192-
.copied()
193-
.filter(move |&num| tcx.crate_name(num) == name)
194-
.map(CrateNum::as_def_id)
195-
}
196-
197-
let tcx = cx.tcx;
198-
199-
let (base, mut path) = match *path {
200-
[primitive] => {
201-
return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)];
202-
},
203-
[base, ref path @ ..] => (base, path),
204-
_ => return Vec::new(),
205-
};
206-
207-
let base_sym = Symbol::intern(base);
208-
209-
let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym {
210-
Some(LOCAL_CRATE.as_def_id())
211-
} else {
212-
None
213-
};
214-
215-
let starts = find_primitive_impls(tcx, base)
216-
.chain(find_crates(tcx, base_sym))
217-
.chain(local_crate)
218-
.map(|id| Res::Def(tcx.def_kind(id), id));
219-
220-
let mut resolutions: Vec<Res> = starts.collect();
221-
222-
while let [segment, rest @ ..] = path {
223-
path = rest;
224-
let segment = Symbol::intern(segment);
225-
226-
resolutions = resolutions
227-
.into_iter()
228-
.filter_map(|res| res.opt_def_id())
229-
.flat_map(|def_id| {
230-
// When the current def_id is e.g. `struct S`, check the impl items in
231-
// `impl S { ... }`
232-
let inherent_impl_children = tcx
233-
.inherent_impls(def_id)
234-
.into_iter()
235-
.flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
236-
237-
let direct_children = item_children_by_name(tcx, def_id, segment);
238-
239-
inherent_impl_children.chain(direct_children)
240-
})
241-
.collect();
242-
}
243-
244-
resolutions
245-
}
246-
247-
pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
248-
def_path_res(cx, path)
249-
.into_iter()
250-
.find_map(|res| match res {
251-
Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
252-
_ => None,
253-
})
66+
pub fn find_first_crate<'tcx>(tcx: &TyCtxt<'tcx>, crate_name: Symbol) -> Option<CrateNum> {
67+
tcx.crates(())
68+
.iter()
69+
.find(|c| tcx.crate_name(**c) == crate_name)
70+
.copied()
25471
}
25572

256-
// These are special variants made from the above functions.
257-
/// Resolves a def path like `std::vec::Vec`, but searches only local crate
258-
///
259-
/// Also returns multiple results when there are multiple paths under the same name e.g. `std::vec`
260-
/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
261-
///
262-
/// This function is less expensive than `def_path_res` and should be used sparingly.
263-
pub fn def_local_res(cx: &LateContext<'_>, path: &str) -> Vec<Res> {
264-
let tcx = cx.tcx;
265-
let local_crate = LOCAL_CRATE.as_def_id();
266-
let starts = Res::Def(tcx.def_kind(local_crate), local_crate);
267-
let mut resolutions: Vec<Res> = vec![starts];
268-
let segment = Symbol::intern(path);
269-
270-
resolutions = resolutions
271-
.into_iter()
272-
.filter_map(|res| res.opt_def_id())
273-
.flat_map(|def_id| {
274-
// When the current def_id is e.g. `struct S`, check the impl items in
275-
// `impl S { ... }`
276-
let inherent_impl_children = tcx
277-
.inherent_impls(def_id)
278-
.into_iter()
279-
.flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
280-
281-
let direct_children = item_children_by_name(tcx, def_id, segment);
282-
283-
inherent_impl_children.chain(direct_children)
284-
})
285-
.collect();
286-
287-
resolutions
73+
pub fn trait_in_crate<'tcx>(
74+
tcx: &TyCtxt<'tcx>,
75+
krate: CrateNum,
76+
trait_sym: Symbol,
77+
) -> Option<DefId> {
78+
tcx.traits(krate)
79+
.iter()
80+
.find(|id| tcx.opt_item_name(**id) == Some(trait_sym))
81+
.copied()
28882
}
28983

290-
pub fn get_local_trait_def_id(cx: &LateContext<'_>, path: &str) -> Option<DefId> {
291-
def_local_res(cx, path)
292-
.into_iter()
293-
.find_map(|res| match res {
294-
Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
295-
_ => None,
296-
})
297-
}
84+
/*
85+
Stuff copied from clippy:
86+
*/
29887

29988
/// Checks whether a type implements a trait.
30089
/// The function returns false in case the type contains an inference variable.
30190
///
302-
/// See:
303-
/// * [`get_trait_def_id`](super::get_trait_def_id) to get a trait [`DefId`].
304-
/// * [Common tools for writing lints] for an example how to use this function and other options.
91+
/// See [Common tools for writing lints] for an example how to use this function and other options.
30592
///
30693
/// [Common tools for writing lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/common_tools_writing_lints.md#checking-if-a-type-implements-a-specific-trait
30794
pub fn implements_trait<'tcx>(
30895
cx: &LateContext<'tcx>,
30996
ty: Ty<'tcx>,
31097
trait_id: DefId,
311-
ty_params: &[GenericArg<'tcx>],
98+
args: &[GenericArg<'tcx>],
31299
) -> bool {
313-
implements_trait_with_env(
100+
implements_trait_with_env_from_iter(
314101
cx.tcx,
315102
cx.typing_env(),
316103
ty,
317104
trait_id,
318-
ty_params.iter().map(|&arg| Some(arg)),
105+
None,
106+
args.iter().map(|&x| Some(x)),
319107
)
320108
}
321109

322-
/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
323-
pub fn implements_trait_with_env<'tcx>(
110+
/// Same as `implements_trait_from_env` but takes the arguments as an iterator.
111+
pub fn implements_trait_with_env_from_iter<'tcx>(
324112
tcx: TyCtxt<'tcx>,
325-
typing_env: TypingEnv<'tcx>,
326-
ty: ty::Ty<'tcx>,
113+
typing_env: ty::TypingEnv<'tcx>,
114+
ty: Ty<'tcx>,
327115
trait_id: DefId,
328-
ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>,
116+
callee_id: Option<DefId>,
117+
args: impl IntoIterator<Item = impl Into<Option<GenericArg<'tcx>>>>,
329118
) -> bool {
119+
// Clippy shouldn't have infer types
120+
assert!(!ty.has_infer());
121+
122+
// If a `callee_id` is passed, then we assert that it is a body owner
123+
// through calling `body_owner_kind`, which would panic if the callee
124+
// does not have a body.
125+
if let Some(callee_id) = callee_id {
126+
let _ = tcx.hir_body_owner_kind(callee_id);
127+
}
128+
330129
let ty = tcx.erase_regions(ty);
331130
if ty.has_escaping_bound_vars() {
332131
return false;
333132
}
334133

335134
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
336-
let ty_params = tcx.mk_args_from_iter(
337-
ty_params
338-
.into_iter()
339-
.map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())),
135+
let args = args
136+
.into_iter()
137+
.map(|arg| {
138+
arg.into()
139+
.unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())
140+
})
141+
.collect::<Vec<_>>();
142+
143+
let trait_ref = TraitRef::new(
144+
tcx,
145+
trait_id,
146+
[GenericArg::from(ty)].into_iter().chain(args),
340147
);
148+
149+
debug_assert!(
150+
matches!(tcx.def_kind(trait_id), DefKind::Trait | DefKind::TraitAlias),
151+
"`DefId` must belong to a trait or trait alias"
152+
);
153+
154+
let obligation = Obligation {
155+
cause: ObligationCause::dummy(),
156+
param_env,
157+
recursion_depth: 0,
158+
predicate: trait_ref.upcast(tcx),
159+
};
341160
infcx
342-
.type_implements_trait(
343-
trait_id,
344-
// for some unknown reason we need to have vec here
345-
// clippy has array
346-
vec![ty.into()].into_iter().chain(ty_params),
347-
param_env,
348-
)
349-
.must_apply_modulo_regions()
161+
.evaluate_obligation(&obligation)
162+
.is_ok_and(EvaluationResult::must_apply_modulo_regions)
350163
}

0 commit comments

Comments
 (0)