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, Instance, TyCtxt, TypeFoldable}
;
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}
;
13 #[instrument(level = "debug", skip(tcx))]
14 fn resolve_instance
<'tcx
>(
16 key
: ty
::ParamEnvAnd
<'tcx
, (DefId
, SubstsRef
<'tcx
>)>,
17 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
18 let (param_env
, (did
, substs
)) = key
.into_parts();
19 if let Some(did
) = did
.as_local() {
20 if let Some(param_did
) = tcx
.opt_const_param_of(did
) {
21 return tcx
.resolve_instance_of_const_arg(param_env
.and((did
, param_did
, substs
)));
25 inner_resolve_instance(tcx
, param_env
.and((ty
::WithOptConstParam
::unknown(did
), substs
)))
28 fn resolve_instance_of_const_arg
<'tcx
>(
30 key
: ty
::ParamEnvAnd
<'tcx
, (LocalDefId
, DefId
, SubstsRef
<'tcx
>)>,
31 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
32 let (param_env
, (did
, const_param_did
, substs
)) = key
.into_parts();
33 inner_resolve_instance(
36 ty
::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) }
,
42 #[instrument(level = "debug", skip(tcx))]
43 fn inner_resolve_instance
<'tcx
>(
45 key
: ty
::ParamEnvAnd
<'tcx
, (ty
::WithOptConstParam
<DefId
>, SubstsRef
<'tcx
>)>,
46 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
47 let (param_env
, (def
, substs
)) = key
.into_parts();
49 let result
= if let Some(trait_def_id
) = tcx
.trait_of_item(def
.did
) {
50 debug
!(" => associated item, attempting to find impl in param_env {:#?}", param_env
);
51 let item
= tcx
.associated_item(def
.did
);
52 resolve_associated_item(tcx
, &item
, param_env
, trait_def_id
, substs
)
54 let ty
= tcx
.type_of(def
.def_id_for_type_of());
55 let item_type
= tcx
.subst_and_normalize_erasing_regions(substs
, param_env
, ty
);
57 let def
= match *item_type
.kind() {
60 let f
= item_type
.fn_sig(tcx
);
61 f
.abi() == Abi
::RustIntrinsic
|| f
.abi() == Abi
::PlatformIntrinsic
64 debug
!(" => intrinsic");
65 ty
::InstanceDef
::Intrinsic(def
.did
)
67 ty
::FnDef(def_id
, substs
) if Some(def_id
) == tcx
.lang_items().drop_in_place_fn() => {
68 let ty
= substs
.type_at(0);
70 if ty
.needs_drop(tcx
, param_env
) {
71 debug
!(" => nontrivial drop glue");
80 // Drop shims can only be built from ADTs.
84 ty
::InstanceDef
::DropGlue(def_id
, Some(ty
))
86 debug
!(" => trivial drop glue");
87 ty
::InstanceDef
::DropGlue(def_id
, None
)
91 debug
!(" => free item");
92 ty
::InstanceDef
::Item(def
)
95 Ok(Some(Instance { def, substs }
))
97 debug
!("inner_resolve_instance: result={:?}", result
);
101 fn resolve_associated_item
<'tcx
>(
103 trait_item
: &ty
::AssocItem
,
104 param_env
: ty
::ParamEnv
<'tcx
>,
106 rcvr_substs
: SubstsRef
<'tcx
>,
107 ) -> Result
<Option
<Instance
<'tcx
>>, ErrorReported
> {
108 let def_id
= trait_item
.def_id
;
110 "resolve_associated_item(trait_item={:?}, \
114 def_id
, param_env
, trait_id
, rcvr_substs
117 let trait_ref
= ty
::TraitRef
::from_method(tcx
, trait_id
, rcvr_substs
);
118 let vtbl
= tcx
.codegen_fulfill_obligation((param_env
, ty
::Binder
::bind(trait_ref
)))?
;
120 // Now that we know which impl is being used, we can dispatch to
121 // the actual function:
123 traits
::ImplSource
::UserDefined(impl_data
) => {
125 "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
126 param_env
, trait_item
, rcvr_substs
, impl_data
128 assert
!(!rcvr_substs
.needs_infer());
129 assert
!(!trait_ref
.needs_infer());
131 let trait_def_id
= tcx
.trait_id_of_impl(impl_data
.impl_def_id
).unwrap();
132 let trait_def
= tcx
.trait_def(trait_def_id
);
133 let leaf_def
= trait_def
134 .ancestors(tcx
, impl_data
.impl_def_id
)?
135 .leaf_def(tcx
, trait_item
.ident
, trait_item
.kind
)
137 bug
!("{:?} not found in {:?}", trait_item
, impl_data
.impl_def_id
);
140 let substs
= tcx
.infer_ctxt().enter(|infcx
| {
141 let param_env
= param_env
.with_reveal_all_normalized(tcx
);
142 let substs
= rcvr_substs
.rebase_onto(tcx
, trait_def_id
, impl_data
.substs
);
143 let substs
= translate_substs(
146 impl_data
.impl_def_id
,
148 leaf_def
.defining_node
,
150 infcx
.tcx
.erase_regions(substs
)
153 // Since this is a trait item, we need to see if the item is either a trait default item
154 // or a specialization because we can't resolve those unless we can `Reveal::All`.
155 // NOTE: This should be kept in sync with the similar code in
156 // `rustc_trait_selection::traits::project::assemble_candidates_from_impls()`.
157 let eligible
= if leaf_def
.is_final() {
158 // Non-specializable items are always projectable.
161 // Only reveal a specializable default if we're past type-checking
162 // and the obligation is monomorphic, otherwise passes such as
163 // transmute checking and polymorphic MIR optimizations could
164 // get a result which isn't correct for all monomorphizations.
165 if param_env
.reveal() == Reveal
::All
{
166 !trait_ref
.still_further_specializable()
176 let substs
= tcx
.erase_regions(substs
);
178 // Check if we just resolved an associated `const` declaration from
179 // a `trait` to an associated `const` definition in an `impl`, where
180 // the definition in the `impl` has the wrong type (for which an
181 // error has already been/will be emitted elsewhere).
183 // NB: this may be expensive, we try to skip it in all the cases where
184 // we know the error would've been caught (e.g. in an upstream crate).
186 // A better approach might be to just introduce a query (returning
187 // `Result<(), ErrorReported>`) for the check that `rustc_typeck`
188 // performs (i.e. that the definition's type in the `impl` matches
189 // the declaration in the `trait`), so that we can cheaply check
190 // here if it failed, instead of approximating it.
191 if trait_item
.kind
== ty
::AssocKind
::Const
192 && trait_item
.def_id
!= leaf_def
.item
.def_id
193 && leaf_def
.item
.def_id
.is_local()
195 let normalized_type_of
= |def_id
, substs
| {
196 tcx
.subst_and_normalize_erasing_regions(substs
, param_env
, tcx
.type_of(def_id
))
199 let original_ty
= normalized_type_of(trait_item
.def_id
, rcvr_substs
);
200 let resolved_ty
= normalized_type_of(leaf_def
.item
.def_id
, substs
);
202 if original_ty
!= resolved_ty
{
204 "Instance::resolve: inconsistent associated `const` type: \
205 was `{}: {}` but resolved to `{}: {}`",
206 tcx
.def_path_str_with_substs(trait_item
.def_id
, rcvr_substs
),
208 tcx
.def_path_str_with_substs(leaf_def
.item
.def_id
, substs
),
211 let span
= tcx
.def_span(leaf_def
.item
.def_id
);
212 tcx
.sess
.delay_span_bug(span
, &msg
);
214 return Err(ErrorReported
);
218 Some(ty
::Instance
::new(leaf_def
.item
.def_id
, substs
))
220 traits
::ImplSource
::Generator(generator_data
) => Some(Instance
{
221 def
: ty
::InstanceDef
::Item(ty
::WithOptConstParam
::unknown(
222 generator_data
.generator_def_id
,
224 substs
: generator_data
.substs
,
226 traits
::ImplSource
::Closure(closure_data
) => {
227 let trait_closure_kind
= tcx
.fn_trait_kind_from_lang_item(trait_id
).unwrap();
228 Some(Instance
::resolve_closure(
230 closure_data
.closure_def_id
,
235 traits
::ImplSource
::FnPointer(ref data
) => match data
.fn_ty
.kind() {
236 ty
::FnDef(..) | ty
::FnPtr(..) => Some(Instance
{
237 def
: ty
::InstanceDef
::FnPtrShim(trait_item
.def_id
, data
.fn_ty
),
242 traits
::ImplSource
::Object(ref data
) => {
243 let index
= traits
::get_vtable_index_of_object_method(tcx
, data
, def_id
);
244 Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }
)
246 traits
::ImplSource
::Builtin(..) => {
247 if Some(trait_ref
.def_id
) == tcx
.lang_items().clone_trait() {
248 // FIXME(eddyb) use lang items for methods instead of names.
249 let name
= tcx
.item_name(def_id
);
250 if name
== sym
::clone
{
251 let self_ty
= trait_ref
.self_ty();
253 let is_copy
= self_ty
.is_copy_modulo_regions(tcx
.at(DUMMY_SP
), param_env
);
254 match self_ty
.kind() {
256 ty
::Array(..) | ty
::Closure(..) | ty
::Tuple(..) => {}
257 _
=> return Ok(None
),
261 def
: ty
::InstanceDef
::CloneShim(def_id
, self_ty
),
265 assert_eq
!(name
, sym
::clone_from
);
267 // Use the default `fn clone_from` from `trait Clone`.
268 let substs
= tcx
.erase_regions(rcvr_substs
);
269 Some(ty
::Instance
::new(def_id
, substs
))
275 traits
::ImplSource
::AutoImpl(..)
276 | traits
::ImplSource
::Param(..)
277 | traits
::ImplSource
::TraitAlias(..)
278 | traits
::ImplSource
::DiscriminantKind(..)
279 | traits
::ImplSource
::Pointee(..) => None
,
283 pub fn provide(providers
: &mut ty
::query
::Providers
) {
285 ty
::query
::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers }
;