Skip to content

Commit 8891044

Browse files
committed
Auto merge of #44896 - qmx:move-resolve-to-librustc, r=arielb1
Move monomorphize::resolve() to librustc this moves `monomorphize::resolve(..)` to librustc, and re-enables inlining for some trait methods, fixing #44389 @nikomatsakis I've kept the calls to the new `ty::Instance::resolve(....)` always `.unwrap()`-ing for the moment, how/do you want to add more debugging info via `.unwrap_or()` or something like this? we still have some related `resolve_*` functions on monomorphize, but I wasn't sure moving them was into the scope for this PR too. @eddyb mind to take a look too?
2 parents 61bad30 + 11e141e commit 8891044

File tree

7 files changed

+273
-136
lines changed

7 files changed

+273
-136
lines changed

src/librustc/ty/instance.rs

+211
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
use hir::def_id::DefId;
1212
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;
1317
use util::ppaux;
1418

1519
use std::fmt;
@@ -111,4 +115,211 @@ impl<'a, 'b, 'tcx> Instance<'tcx> {
111115
pub fn def_id(&self) -> DefId {
112116
self.def.def_id()
113117
}
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 }
114325
}

src/librustc_mir/transform/inline.rs

+17-11
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
1818
use rustc::mir::*;
1919
use rustc::mir::transform::{MirPass, MirSource};
2020
use rustc::mir::visit::*;
21-
use rustc::ty::{self, Ty, TyCtxt};
21+
use rustc::ty::{self, Ty, TyCtxt, Instance};
2222
use rustc::ty::subst::{Subst,Substs};
2323

2424
use std::collections::VecDeque;
@@ -78,7 +78,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
7878
let mut callsites = VecDeque::new();
7979

8080
// Only do inlining into fn bodies.
81-
if let MirSource::Fn(_) = self.source {
81+
if let MirSource::Fn(caller_id) = self.source {
8282
for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() {
8383
// Don't inline calls that are in cleanup blocks.
8484
if bb_data.is_cleanup { continue; }
@@ -87,17 +87,23 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
8787
let terminator = bb_data.terminator();
8888
if let TerminatorKind::Call {
8989
func: Operand::Constant(ref f), .. } = terminator.kind {
90-
if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty {
91-
if self.tcx.trait_of_item(callee_def_id).is_none() {
92-
callsites.push_back(CallSite {
93-
callee: callee_def_id,
94-
substs,
95-
bb,
96-
location: terminator.source_info
97-
});
90+
if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty {
91+
let caller_def_id = self.tcx.hir.local_def_id(caller_id);
92+
let param_env = self.tcx.param_env(caller_def_id);
93+
94+
if let Some(instance) = Instance::resolve(self.tcx,
95+
param_env,
96+
callee_def_id,
97+
substs) {
98+
callsites.push_back(CallSite {
99+
callee: instance.def_id(),
100+
substs: instance.substs,
101+
bb,
102+
location: terminator.source_info
103+
});
104+
}
98105
}
99106
}
100-
}
101107
}
102108
}
103109

src/librustc_trans/callee.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ use common::{self, CrateContext};
1919
use consts;
2020
use declare;
2121
use llvm::{self, ValueRef};
22-
use monomorphize::{self, Instance};
22+
use monomorphize::Instance;
2323
use rustc::hir::def_id::DefId;
24-
use rustc::ty::TypeFoldable;
24+
use rustc::ty::{self, TypeFoldable};
25+
use rustc::traits;
2526
use rustc::ty::subst::Substs;
2627
use type_of;
2728

@@ -179,5 +180,13 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
179180
substs: &'tcx Substs<'tcx>)
180181
-> ValueRef
181182
{
182-
get_fn(ccx, monomorphize::resolve(ccx.tcx(), def_id, substs))
183+
get_fn(
184+
ccx,
185+
ty::Instance::resolve(
186+
ccx.tcx(),
187+
ty::ParamEnv::empty(traits::Reveal::All),
188+
def_id,
189+
substs
190+
).unwrap()
191+
)
183192
}

src/librustc_trans/collector.rs

+22-6
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
566566
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
567567
let substs = self.tcx.trans_apply_param_substs(self.param_substs,
568568
&substs);
569-
let instance = monomorphize::resolve(self.tcx, def_id, substs);
569+
let instance = ty::Instance::resolve(self.tcx,
570+
ty::ParamEnv::empty(traits::Reveal::All),
571+
def_id,
572+
substs).unwrap();
570573
collect_neighbours(self.tcx, instance, true, self.output);
571574
}
572575

@@ -587,7 +590,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
587590

588591
let constness = match (self.const_context, &callee_ty.sty) {
589592
(true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => {
590-
let instance = monomorphize::resolve(self.tcx, def_id, substs);
593+
let instance =
594+
ty::Instance::resolve(self.tcx,
595+
ty::ParamEnv::empty(traits::Reveal::All),
596+
def_id,
597+
substs).unwrap();
591598
Some(instance)
592599
}
593600
_ => None
@@ -657,7 +664,10 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
657664
output: &mut Vec<TransItem<'tcx>>)
658665
{
659666
if let ty::TyFnDef(def_id, substs) = ty.sty {
660-
let instance = monomorphize::resolve(tcx, def_id, substs);
667+
let instance = ty::Instance::resolve(tcx,
668+
ty::ParamEnv::empty(traits::Reveal::All),
669+
def_id,
670+
substs).unwrap();
661671
visit_instance_use(tcx, instance, is_direct_call, output);
662672
}
663673
}
@@ -845,7 +855,11 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
845855
// Walk all methods of the trait, including those of its supertraits
846856
let methods = traits::get_vtable_methods(tcx, poly_trait_ref);
847857
let methods = methods.filter_map(|method| method)
848-
.map(|(def_id, substs)| monomorphize::resolve(tcx, def_id, substs))
858+
.map(|(def_id, substs)| ty::Instance::resolve(
859+
tcx,
860+
ty::ParamEnv::empty(traits::Reveal::All),
861+
def_id,
862+
substs).unwrap())
849863
.filter(|&instance| should_trans_locally(tcx, &instance))
850864
.map(|instance| create_fn_trans_item(instance));
851865
output.extend(methods);
@@ -1000,8 +1014,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10001014
continue;
10011015
}
10021016

1003-
let instance =
1004-
monomorphize::resolve(tcx, method.def_id, callee_substs);
1017+
let instance = ty::Instance::resolve(tcx,
1018+
ty::ParamEnv::empty(traits::Reveal::All),
1019+
method.def_id,
1020+
callee_substs).unwrap();
10051021

10061022
let trans_item = create_fn_trans_item(instance);
10071023
if trans_item.is_instantiable(tcx) && should_trans_locally(tcx, &instance) {

src/librustc_trans/mir/block.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc::middle::lang_items;
1313
use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind};
1414
use rustc::ty::{self, Ty, TypeFoldable};
1515
use rustc::ty::layout::{self, LayoutTyper};
16+
use rustc::traits;
1617
use rustc::mir;
1718
use abi::{Abi, FnType, ArgType};
1819
use adt;
@@ -429,7 +430,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
429430

430431
let (instance, mut llfn) = match callee.ty.sty {
431432
ty::TyFnDef(def_id, substs) => {
432-
(Some(monomorphize::resolve(bcx.ccx.tcx(), def_id, substs)),
433+
(Some(ty::Instance::resolve(bcx.ccx.tcx(),
434+
ty::ParamEnv::empty(traits::Reveal::All),
435+
def_id,
436+
substs).unwrap()),
433437
None)
434438
}
435439
ty::TyFnPtr(_) => {

0 commit comments

Comments
 (0)