|
10 | 10 |
|
11 | 11 | use hir::def_id::DefId;
|
12 | 12 | use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
|
| 13 | +use ty::subst::{Kind, Subst}; |
| 14 | +use traits; |
| 15 | +use syntax::abi::Abi; |
| 16 | +use syntax::codemap::DUMMY_SP; |
13 | 17 | use util::ppaux;
|
14 | 18 |
|
15 | 19 | use std::fmt;
|
@@ -111,4 +115,211 @@ impl<'a, 'b, 'tcx> Instance<'tcx> {
|
111 | 115 | pub fn def_id(&self) -> DefId {
|
112 | 116 | self.def.def_id()
|
113 | 117 | }
|
| 118 | + |
| 119 | + /// Resolve a (def_id, substs) pair to an (optional) instance -- most commonly, |
| 120 | + /// this is used to find the precise code that will run for a trait method invocation, |
| 121 | + /// if known. |
| 122 | + /// |
| 123 | + /// Returns `None` if we cannot resolve `Instance` to a specific instance. |
| 124 | + /// For example, in a context like this, |
| 125 | + /// |
| 126 | + /// ``` |
| 127 | + /// fn foo<T: Debug>(t: T) { ... } |
| 128 | + /// ``` |
| 129 | + /// |
| 130 | + /// trying to resolve `Debug::fmt` applied to `T` will yield `None`, because we do not |
| 131 | + /// know what code ought to run. (Note that this setting is also affected by the |
| 132 | + /// `RevealMode` in the parameter environment.) |
| 133 | + /// |
| 134 | + /// Presuming that coherence and type-check have succeeded, if this method is invoked |
| 135 | + /// in a monomorphic context (i.e., like during trans), then it is guaranteed to return |
| 136 | + /// `Some`. |
| 137 | + pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
| 138 | + param_env: ty::ParamEnv<'tcx>, |
| 139 | + def_id: DefId, |
| 140 | + substs: &'tcx Substs<'tcx>) -> Option<Instance<'tcx>> { |
| 141 | + debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); |
| 142 | + let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { |
| 143 | + debug!(" => associated item, attempting to find impl"); |
| 144 | + let item = tcx.associated_item(def_id); |
| 145 | + resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) |
| 146 | + } else { |
| 147 | + let ty = tcx.type_of(def_id); |
| 148 | + let item_type = tcx.trans_apply_param_substs(substs, &ty); |
| 149 | + |
| 150 | + let def = match item_type.sty { |
| 151 | + ty::TyFnDef(..) if { |
| 152 | + let f = item_type.fn_sig(tcx); |
| 153 | + f.abi() == Abi::RustIntrinsic || |
| 154 | + f.abi() == Abi::PlatformIntrinsic |
| 155 | + } => |
| 156 | + { |
| 157 | + debug!(" => intrinsic"); |
| 158 | + ty::InstanceDef::Intrinsic(def_id) |
| 159 | + } |
| 160 | + _ => { |
| 161 | + if Some(def_id) == tcx.lang_items().drop_in_place_fn() { |
| 162 | + let ty = substs.type_at(0); |
| 163 | + if ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) { |
| 164 | + debug!(" => nontrivial drop glue"); |
| 165 | + ty::InstanceDef::DropGlue(def_id, Some(ty)) |
| 166 | + } else { |
| 167 | + debug!(" => trivial drop glue"); |
| 168 | + ty::InstanceDef::DropGlue(def_id, None) |
| 169 | + } |
| 170 | + } else { |
| 171 | + debug!(" => free item"); |
| 172 | + ty::InstanceDef::Item(def_id) |
| 173 | + } |
| 174 | + } |
| 175 | + }; |
| 176 | + Some(Instance { |
| 177 | + def: def, |
| 178 | + substs: substs |
| 179 | + }) |
| 180 | + }; |
| 181 | + debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); |
| 182 | + result |
| 183 | + } |
| 184 | +} |
| 185 | + |
| 186 | +fn resolve_closure<'a, 'tcx>( |
| 187 | + tcx: TyCtxt<'a, 'tcx, 'tcx>, |
| 188 | + def_id: DefId, |
| 189 | + substs: ty::ClosureSubsts<'tcx>, |
| 190 | + requested_kind: ty::ClosureKind) |
| 191 | +-> Instance<'tcx> |
| 192 | +{ |
| 193 | + let actual_kind = tcx.closure_kind(def_id); |
| 194 | + |
| 195 | + match needs_fn_once_adapter_shim(actual_kind, requested_kind) { |
| 196 | + Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), |
| 197 | + _ => Instance::new(def_id, substs.substs) |
| 198 | + } |
| 199 | +} |
| 200 | + |
| 201 | +fn resolve_associated_item<'a, 'tcx>( |
| 202 | + tcx: TyCtxt<'a, 'tcx, 'tcx>, |
| 203 | + trait_item: &ty::AssociatedItem, |
| 204 | + param_env: ty::ParamEnv<'tcx>, |
| 205 | + trait_id: DefId, |
| 206 | + rcvr_substs: &'tcx Substs<'tcx> |
| 207 | + ) -> Option<Instance<'tcx>> { |
| 208 | + let def_id = trait_item.def_id; |
| 209 | + debug!("resolve_associated_item(trait_item={:?}, \ |
| 210 | + trait_id={:?}, \ |
| 211 | + rcvr_substs={:?})", |
| 212 | + def_id, trait_id, rcvr_substs); |
| 213 | + |
| 214 | + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); |
| 215 | + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, param_env, ty::Binder(trait_ref)); |
| 216 | + |
| 217 | + // Now that we know which impl is being used, we can dispatch to |
| 218 | + // the actual function: |
| 219 | + match vtbl { |
| 220 | + traits::VtableImpl(impl_data) => { |
| 221 | + let (def_id, substs) = traits::find_associated_item( |
| 222 | + tcx, trait_item, rcvr_substs, &impl_data); |
| 223 | + let substs = tcx.erase_regions(&substs); |
| 224 | + Some(ty::Instance::new(def_id, substs)) |
| 225 | + } |
| 226 | + traits::VtableGenerator(closure_data) => { |
| 227 | + Some(Instance { |
| 228 | + def: ty::InstanceDef::Item(closure_data.closure_def_id), |
| 229 | + substs: closure_data.substs.substs |
| 230 | + }) |
| 231 | + } |
| 232 | + traits::VtableClosure(closure_data) => { |
| 233 | + let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); |
| 234 | + Some(resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs, |
| 235 | + trait_closure_kind)) |
| 236 | + } |
| 237 | + traits::VtableFnPointer(ref data) => { |
| 238 | + Some(Instance { |
| 239 | + def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), |
| 240 | + substs: rcvr_substs |
| 241 | + }) |
| 242 | + } |
| 243 | + traits::VtableObject(ref data) => { |
| 244 | + let index = tcx.get_vtable_index_of_object_method(data, def_id); |
| 245 | + Some(Instance { |
| 246 | + def: ty::InstanceDef::Virtual(def_id, index), |
| 247 | + substs: rcvr_substs |
| 248 | + }) |
| 249 | + } |
| 250 | + traits::VtableBuiltin(..) => { |
| 251 | + if let Some(_) = tcx.lang_items().clone_trait() { |
| 252 | + Some(Instance { |
| 253 | + def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), |
| 254 | + substs: rcvr_substs |
| 255 | + }) |
| 256 | + } else { |
| 257 | + None |
| 258 | + } |
| 259 | + } |
| 260 | + traits::VtableDefaultImpl(..) | traits::VtableParam(..) => None |
| 261 | + } |
| 262 | +} |
| 263 | + |
| 264 | +fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind, |
| 265 | + trait_closure_kind: ty::ClosureKind) |
| 266 | + -> Result<bool, ()> |
| 267 | +{ |
| 268 | + match (actual_closure_kind, trait_closure_kind) { |
| 269 | + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | |
| 270 | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | |
| 271 | + (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { |
| 272 | + // No adapter needed. |
| 273 | + Ok(false) |
| 274 | + } |
| 275 | + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { |
| 276 | + // The closure fn `llfn` is a `fn(&self, ...)`. We want a |
| 277 | + // `fn(&mut self, ...)`. In fact, at trans time, these are |
| 278 | + // basically the same thing, so we can just return llfn. |
| 279 | + Ok(false) |
| 280 | + } |
| 281 | + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | |
| 282 | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { |
| 283 | + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut |
| 284 | + // self, ...)`. We want a `fn(self, ...)`. We can produce |
| 285 | + // this by doing something like: |
| 286 | + // |
| 287 | + // fn call_once(self, ...) { call_mut(&self, ...) } |
| 288 | + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } |
| 289 | + // |
| 290 | + // These are both the same at trans time. |
| 291 | + Ok(true) |
| 292 | + } |
| 293 | + (ty::ClosureKind::FnMut, _) | |
| 294 | + (ty::ClosureKind::FnOnce, _) => Err(()) |
| 295 | + } |
| 296 | +} |
| 297 | + |
| 298 | +fn fn_once_adapter_instance<'a, 'tcx>( |
| 299 | + tcx: TyCtxt<'a, 'tcx, 'tcx>, |
| 300 | + closure_did: DefId, |
| 301 | + substs: ty::ClosureSubsts<'tcx>, |
| 302 | + ) -> Instance<'tcx> { |
| 303 | + debug!("fn_once_adapter_shim({:?}, {:?})", |
| 304 | + closure_did, |
| 305 | + substs); |
| 306 | + let fn_once = tcx.lang_items().fn_once_trait().unwrap(); |
| 307 | + let call_once = tcx.associated_items(fn_once) |
| 308 | + .find(|it| it.kind == ty::AssociatedKind::Method) |
| 309 | + .unwrap().def_id; |
| 310 | + let def = ty::InstanceDef::ClosureOnceShim { call_once }; |
| 311 | + |
| 312 | + let self_ty = tcx.mk_closure_from_closure_substs( |
| 313 | + closure_did, substs); |
| 314 | + |
| 315 | + let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs); |
| 316 | + let sig = tcx.erase_late_bound_regions_and_normalize(&sig); |
| 317 | + assert_eq!(sig.inputs().len(), 1); |
| 318 | + let substs = tcx.mk_substs([ |
| 319 | + Kind::from(self_ty), |
| 320 | + Kind::from(sig.inputs()[0]), |
| 321 | + ].iter().cloned()); |
| 322 | + |
| 323 | + debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); |
| 324 | + Instance { def, substs } |
114 | 325 | }
|
0 commit comments