1 use rustc_errors
::ErrorReported
;
2 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
3 use rustc_infer
::infer
::TyCtxtInferExt
;
4 use rustc_middle
::ty
::subst
::SubstsRef
;
5 use rustc_middle
::ty
::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor}
;
6 use rustc_span
::{sym, DUMMY_SP}
;
7 use rustc_target
::spec
::abi
::Abi
;
8 use rustc_trait_selection
::traits
;
9 use traits
::{translate_substs, Reveal}
;
11 use rustc_data_structures
::sso
::SsoHashSet
;
12 use std
::collections
::btree_map
::Entry
;
13 use std
::collections
::BTreeMap
;
14 use std
::ops
::ControlFlow
;
18 // FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
19 // outside of `resolve_associated_item`. It's just to address #64494,
20 // #83765, and #85848 which are creating bound types/regions that lose
21 // their `Binder` *unintentionally*.
22 // It's ideal to remove `BoundVarsCollector` and just use
23 // `ty::Binder::*` methods but we use this stopgap until we figure out
25 struct BoundVarsCollector
<'tcx
> {
26 binder_index
: ty
::DebruijnIndex
,
27 vars
: BTreeMap
<u32, ty
::BoundVariableKind
>,
28 // We may encounter the same variable at different levels of binding, so
29 // this can't just be `Ty`
30 visited
: SsoHashSet
<(ty
::DebruijnIndex
, Ty
<'tcx
>)>,
33 impl<'tcx
> BoundVarsCollector
<'tcx
> {
36 binder_index
: ty
::INNERMOST
,
37 vars
: BTreeMap
::new(),
38 visited
: SsoHashSet
::default(),
42 fn into_vars(self, tcx
: TyCtxt
<'tcx
>) -> &'tcx ty
::List
<ty
::BoundVariableKind
> {
43 let max
= self.vars
.iter().map(|(k
, _
)| *k
).max().unwrap_or(0);
45 if let None
= self.vars
.get(&i
) {
46 panic
!("Unknown variable: {:?}", i
);
50 tcx
.mk_bound_variable_kinds(self.vars
.into_iter().map(|(_
, v
)| v
))
54 impl<'tcx
> TypeVisitor
<'tcx
> for BoundVarsCollector
<'tcx
> {
57 fn visit_binder
<T
: TypeFoldable
<'tcx
>>(
60 ) -> ControlFlow
<Self::BreakTy
> {
61 self.binder_index
.shift_in(1);
62 let result
= t
.super_visit_with(self);
63 self.binder_index
.shift_out(1);
67 fn visit_ty(&mut self, t
: Ty
<'tcx
>) -> ControlFlow
<Self::BreakTy
> {
68 if t
.outer_exclusive_binder() < self.binder_index
69 || !self.visited
.insert((self.binder_index
, t
))
71 return ControlFlow
::CONTINUE
;
74 ty
::Bound(debruijn
, bound_ty
) if debruijn
== self.binder_index
=> {
75 match self.vars
.entry(bound_ty
.var
.as_u32()) {
76 Entry
::Vacant(entry
) => {
77 entry
.insert(ty
::BoundVariableKind
::Ty(bound_ty
.kind
));
79 Entry
::Occupied(entry
) => match entry
.get() {
80 ty
::BoundVariableKind
::Ty(_
) => {}
81 _
=> bug
!("Conflicting bound vars"),
89 t
.super_visit_with(self)
92 fn visit_region(&mut self, r
: ty
::Region
<'tcx
>) -> ControlFlow
<Self::BreakTy
> {
94 ty
::ReLateBound(index
, br
) if *index
== self.binder_index
=> {
95 match self.vars
.entry(br
.var
.as_u32()) {
96 Entry
::Vacant(entry
) => {
97 entry
.insert(ty
::BoundVariableKind
::Region(br
.kind
));
99 Entry
::Occupied(entry
) => match entry
.get() {
100 ty
::BoundVariableKind
::Region(_
) => {}
101 _
=> bug
!("Conflicting bound vars"),
109 r
.super_visit_with(self)
113 #[instrument(level = "debug", skip(tcx))]
114 fn resolve_instance
<'tcx
>(
116 key
: ty
::ParamEnvAnd
<'tcx
, (DefId
, SubstsRef
<'tcx
>)>,
117 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
118 let (param_env
, (did
, substs
)) = key
.into_parts();
119 if let Some(did
) = did
.as_local() {
120 if let Some(param_did
) = tcx
.opt_const_param_of(did
) {
121 return tcx
.resolve_instance_of_const_arg(param_env
.and((did
, param_did
, substs
)));
125 inner_resolve_instance(tcx
, param_env
.and((ty
::WithOptConstParam
::unknown(did
), substs
)))
128 fn resolve_instance_of_const_arg
<'tcx
>(
130 key
: ty
::ParamEnvAnd
<'tcx
, (LocalDefId
, DefId
, SubstsRef
<'tcx
>)>,
131 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
132 let (param_env
, (did
, const_param_did
, substs
)) = key
.into_parts();
133 inner_resolve_instance(
136 ty
::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) }
,
142 #[instrument(level = "debug", skip(tcx))]
143 fn inner_resolve_instance
<'tcx
>(
145 key
: ty
::ParamEnvAnd
<'tcx
, (ty
::WithOptConstParam
<DefId
>, SubstsRef
<'tcx
>)>,
146 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
147 let (param_env
, (def
, substs
)) = key
.into_parts();
149 let result
= if let Some(trait_def_id
) = tcx
.trait_of_item(def
.did
) {
150 debug
!(" => associated item, attempting to find impl in param_env {:#?}", param_env
);
151 let item
= tcx
.associated_item(def
.did
);
152 resolve_associated_item(tcx
, &item
, param_env
, trait_def_id
, substs
)
154 let ty
= tcx
.type_of(def
.def_id_for_type_of());
155 let item_type
= tcx
.subst_and_normalize_erasing_regions(substs
, param_env
, ty
);
157 let def
= match *item_type
.kind() {
160 let f
= item_type
.fn_sig(tcx
);
161 f
.abi() == Abi
::RustIntrinsic
|| f
.abi() == Abi
::PlatformIntrinsic
164 debug
!(" => intrinsic");
165 ty
::InstanceDef
::Intrinsic(def
.did
)
167 ty
::FnDef(def_id
, substs
) if Some(def_id
) == tcx
.lang_items().drop_in_place_fn() => {
168 let ty
= substs
.type_at(0);
170 if ty
.needs_drop(tcx
, param_env
) {
171 debug
!(" => nontrivial drop glue");
179 | ty
::Slice(..) => {}
180 // Drop shims can only be built from ADTs.
181 _
=> return Ok(None
),
184 ty
::InstanceDef
::DropGlue(def_id
, Some(ty
))
186 debug
!(" => trivial drop glue");
187 ty
::InstanceDef
::DropGlue(def_id
, None
)
191 debug
!(" => free item");
192 ty
::InstanceDef
::Item(def
)
195 Ok(Some(Instance { def, substs }
))
197 debug
!("inner_resolve_instance: result={:?}", result
);
201 fn resolve_associated_item
<'tcx
>(
203 trait_item
: &ty
::AssocItem
,
204 param_env
: ty
::ParamEnv
<'tcx
>,
206 rcvr_substs
: SubstsRef
<'tcx
>,
207 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
208 let def_id
= trait_item
.def_id
;
210 "resolve_associated_item(trait_item={:?}, \
214 def_id
, param_env
, trait_id
, rcvr_substs
217 let trait_ref
= ty
::TraitRef
::from_method(tcx
, trait_id
, rcvr_substs
);
219 // See FIXME on `BoundVarsCollector`.
220 let mut bound_vars_collector
= BoundVarsCollector
::new();
221 trait_ref
.visit_with(&mut bound_vars_collector
);
222 let trait_binder
= ty
::Binder
::bind_with_vars(trait_ref
, bound_vars_collector
.into_vars(tcx
));
223 let vtbl
= tcx
.codegen_fulfill_obligation((param_env
, trait_binder
))?
;
225 // Now that we know which impl is being used, we can dispatch to
226 // the actual function:
228 traits
::ImplSource
::UserDefined(impl_data
) => {
230 "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
231 param_env
, trait_item
, rcvr_substs
, impl_data
233 assert
!(!rcvr_substs
.needs_infer());
234 assert
!(!trait_ref
.needs_infer());
236 let trait_def_id
= tcx
.trait_id_of_impl(impl_data
.impl_def_id
).unwrap();
237 let trait_def
= tcx
.trait_def(trait_def_id
);
238 let leaf_def
= trait_def
239 .ancestors(tcx
, impl_data
.impl_def_id
)?
240 .leaf_def(tcx
, trait_item
.ident
, trait_item
.kind
)
242 bug
!("{:?} not found in {:?}", trait_item
, impl_data
.impl_def_id
);
245 let substs
= tcx
.infer_ctxt().enter(|infcx
| {
246 let param_env
= param_env
.with_reveal_all_normalized(tcx
);
247 let substs
= rcvr_substs
.rebase_onto(tcx
, trait_def_id
, impl_data
.substs
);
248 let substs
= translate_substs(
251 impl_data
.impl_def_id
,
253 leaf_def
.defining_node
,
255 infcx
.tcx
.erase_regions(substs
)
258 // Since this is a trait item, we need to see if the item is either a trait default item
259 // or a specialization because we can't resolve those unless we can `Reveal::All`.
260 // NOTE: This should be kept in sync with the similar code in
261 // `rustc_trait_selection::traits::project::assemble_candidates_from_impls()`.
262 let eligible
= if leaf_def
.is_final() {
263 // Non-specializable items are always projectable.
266 // Only reveal a specializable default if we're past type-checking
267 // and the obligation is monomorphic, otherwise passes such as
268 // transmute checking and polymorphic MIR optimizations could
269 // get a result which isn't correct for all monomorphizations.
270 if param_env
.reveal() == Reveal
::All
{
271 !trait_ref
.still_further_specializable()
281 let substs
= tcx
.erase_regions(substs
);
283 // Check if we just resolved an associated `const` declaration from
284 // a `trait` to an associated `const` definition in an `impl`, where
285 // the definition in the `impl` has the wrong type (for which an
286 // error has already been/will be emitted elsewhere).
288 // NB: this may be expensive, we try to skip it in all the cases where
289 // we know the error would've been caught (e.g. in an upstream crate).
291 // A better approach might be to just introduce a query (returning
292 // `Result<(), ErrorReported>`) for the check that `rustc_typeck`
293 // performs (i.e. that the definition's type in the `impl` matches
294 // the declaration in the `trait`), so that we can cheaply check
295 // here if it failed, instead of approximating it.
296 if trait_item
.kind
== ty
::AssocKind
::Const
297 && trait_item
.def_id
!= leaf_def
.item
.def_id
298 && leaf_def
.item
.def_id
.is_local()
300 let normalized_type_of
= |def_id
, substs
| {
301 tcx
.subst_and_normalize_erasing_regions(substs
, param_env
, tcx
.type_of(def_id
))
304 let original_ty
= normalized_type_of(trait_item
.def_id
, rcvr_substs
);
305 let resolved_ty
= normalized_type_of(leaf_def
.item
.def_id
, substs
);
307 if original_ty
!= resolved_ty
{
309 "Instance::resolve: inconsistent associated `const` type: \
310 was `{}: {}` but resolved to `{}: {}`",
311 tcx
.def_path_str_with_substs(trait_item
.def_id
, rcvr_substs
),
313 tcx
.def_path_str_with_substs(leaf_def
.item
.def_id
, substs
),
316 let span
= tcx
.def_span(leaf_def
.item
.def_id
);
317 tcx
.sess
.delay_span_bug(span
, &msg
);
319 return Err(ErrorReported
);
323 Some(ty
::Instance
::new(leaf_def
.item
.def_id
, substs
))
325 traits
::ImplSource
::Generator(generator_data
) => Some(Instance
{
326 def
: ty
::InstanceDef
::Item(ty
::WithOptConstParam
::unknown(
327 generator_data
.generator_def_id
,
329 substs
: generator_data
.substs
,
331 traits
::ImplSource
::Closure(closure_data
) => {
332 let trait_closure_kind
= tcx
.fn_trait_kind_from_lang_item(trait_id
).unwrap();
333 Some(Instance
::resolve_closure(
335 closure_data
.closure_def_id
,
340 traits
::ImplSource
::FnPointer(ref data
) => match data
.fn_ty
.kind() {
341 ty
::FnDef(..) | ty
::FnPtr(..) => Some(Instance
{
342 def
: ty
::InstanceDef
::FnPtrShim(trait_item
.def_id
, data
.fn_ty
),
347 traits
::ImplSource
::Object(ref data
) => {
348 let index
= traits
::get_vtable_index_of_object_method(tcx
, data
, def_id
);
349 Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }
)
351 traits
::ImplSource
::Builtin(..) => {
352 if Some(trait_ref
.def_id
) == tcx
.lang_items().clone_trait() {
353 // FIXME(eddyb) use lang items for methods instead of names.
354 let name
= tcx
.item_name(def_id
);
355 if name
== sym
::clone
{
356 let self_ty
= trait_ref
.self_ty();
358 let is_copy
= self_ty
.is_copy_modulo_regions(tcx
.at(DUMMY_SP
), param_env
);
359 match self_ty
.kind() {
361 ty
::Array(..) | ty
::Closure(..) | ty
::Tuple(..) => {}
362 _
=> return Ok(None
),
366 def
: ty
::InstanceDef
::CloneShim(def_id
, self_ty
),
370 assert_eq
!(name
, sym
::clone_from
);
372 // Use the default `fn clone_from` from `trait Clone`.
373 let substs
= tcx
.erase_regions(rcvr_substs
);
374 Some(ty
::Instance
::new(def_id
, substs
))
380 traits
::ImplSource
::AutoImpl(..)
381 | traits
::ImplSource
::Param(..)
382 | traits
::ImplSource
::TraitAlias(..)
383 | traits
::ImplSource
::DiscriminantKind(..)
384 | traits
::ImplSource
::Pointee(..) => None
,
388 pub fn provide(providers
: &mut ty
::query
::Providers
) {
390 ty
::query
::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers }
;