Skip to content

Commit 0b5bc33

Browse files
committed
Implement new operator dispatch semantics.
Key points are: 1. `a + b` maps directly to `Add<A,B>`, where `A` and `B` are the types of `a` and `b`. 2. Indexing and slicing autoderefs consistently.
1 parent 33ef78f commit 0b5bc33

15 files changed

+827
-221
lines changed

src/librustc/middle/ty.rs

+15
Original file line numberDiff line numberDiff line change
@@ -5566,3 +5566,18 @@ pub fn with_freevars<T>(tcx: &ty::ctxt, fid: ast::NodeId, f: |&[Freevar]| -> T)
55665566
Some(d) => f(d.as_slice())
55675567
}
55685568
}
5569+
5570+
impl AutoAdjustment {
5571+
pub fn is_identity(&self) -> bool {
5572+
match *self {
5573+
AdjustAddEnv(..) => false,
5574+
AdjustDerefRef(ref r) => r.is_identity(),
5575+
}
5576+
}
5577+
}
5578+
5579+
impl AutoDerefRef {
5580+
pub fn is_identity(&self) -> bool {
5581+
self.autoderefs == 0 && self.autoref.is_none()
5582+
}
5583+
}

src/librustc/middle/typeck/check/method.rs

+237-54
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ use middle::typeck::{MethodOrigin, MethodParam, MethodTypeParam};
9696
use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject, MethodTraitObject};
9797
use middle::typeck::check::regionmanip::replace_late_bound_regions;
9898
use middle::typeck::TypeAndSubsts;
99+
use middle::typeck::check::vtable;
99100
use middle::ty_fold::TypeFoldable;
100101
use util::common::indenter;
101102
use util::ppaux;
@@ -173,46 +174,178 @@ pub fn lookup<'a, 'tcx>(
173174

174175
pub fn lookup_in_trait<'a, 'tcx>(
175176
fcx: &'a FnCtxt<'a, 'tcx>,
176-
177-
// In a call `a.b::<X, Y, ...>(...)`:
178-
span: Span, // The expression `a.b(...)`'s span.
179-
self_expr: Option<&'a ast::Expr>, // The expression `a`, if available.
180-
m_name: ast::Name, // The name `b`.
181-
trait_did: DefId, // The trait to limit the lookup to.
182-
self_ty: ty::t, // The type of `a`.
183-
supplied_tps: &'a [ty::t]) // The list of types X, Y, ... .
177+
span: Span,
178+
self_expr: Option<&'a ast::Expr>,
179+
m_name: ast::Name,
180+
trait_def_id: DefId,
181+
self_ty: ty::t,
182+
opt_input_types: Option<Vec<ty::t>>)
184183
-> Option<MethodCallee>
185184
{
186-
let mut lcx = LookupContext {
187-
fcx: fcx,
188-
span: span,
189-
self_expr: self_expr,
190-
m_name: m_name,
191-
supplied_tps: supplied_tps,
192-
impl_dups: HashSet::new(),
193-
inherent_candidates: Vec::new(),
194-
extension_candidates: Vec::new(),
195-
static_candidates: Vec::new(),
196-
deref_args: check::DoDerefArgs,
197-
check_traits: CheckTraitsOnly,
198-
autoderef_receiver: DontAutoderefReceiver,
199-
};
185+
lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
186+
ty::AutoDerefRef { autoderefs: 0, autoref: None },
187+
self_ty, opt_input_types)
188+
}
200189

201-
debug!("method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_did={})",
190+
pub fn lookup_in_trait_adjusted<'a, 'tcx>(
191+
fcx: &'a FnCtxt<'a, 'tcx>,
192+
span: Span,
193+
self_expr: Option<&'a ast::Expr>,
194+
m_name: ast::Name,
195+
trait_def_id: DefId,
196+
autoderefref: ty::AutoDerefRef,
197+
self_ty: ty::t,
198+
opt_input_types: Option<Vec<ty::t>>)
199+
-> Option<MethodCallee>
200+
{
201+
debug!("method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_def_id={})",
202202
self_ty.repr(fcx.tcx()),
203203
self_expr.repr(fcx.tcx()),
204204
m_name.repr(fcx.tcx()),
205-
trait_did.repr(fcx.tcx()));
205+
trait_def_id.repr(fcx.tcx()));
206+
207+
let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_def_id);
208+
209+
let expected_number_of_input_types = trait_def.generics.types.len(subst::TypeSpace);
210+
let input_types = match opt_input_types {
211+
Some(input_types) => {
212+
assert_eq!(expected_number_of_input_types, input_types.len());
213+
input_types
214+
}
215+
216+
None => {
217+
fcx.inh.infcx.next_ty_vars(expected_number_of_input_types)
218+
}
219+
};
220+
221+
let number_assoc_types = trait_def.generics.types.len(subst::AssocSpace);
222+
let assoc_types = fcx.inh.infcx.next_ty_vars(number_assoc_types);
206223

207-
lcx.push_bound_candidates(self_ty, Some(trait_did));
208-
lcx.push_extension_candidate(trait_did);
224+
assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
225+
assert!(trait_def.generics.regions.is_empty());
209226

210-
// when doing a trait search, ambiguity can't really happen except
211-
// as part of the trait-lookup in general
212-
match lcx.search(self_ty) {
213-
Ok(callee) => Some(callee),
214-
Err(_) => None
227+
// Construct a trait-reference `self_ty : Trait<input_tys>`
228+
let substs = subst::Substs::new_trait(input_types, Vec::new(), assoc_types, self_ty);
229+
let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
230+
231+
// Construct an obligation
232+
let obligation = traits::Obligation::misc(span, trait_ref.clone());
233+
234+
// Now we want to know if this can be matched
235+
let mut selcx = traits::SelectionContext::new(fcx.infcx(),
236+
&fcx.inh.param_env,
237+
fcx);
238+
if !selcx.evaluate_obligation_intracrate(&obligation) {
239+
debug!("--> Cannot match obligation");
240+
return None; // Cannot be matched, no such method resolution is possible.
241+
}
242+
243+
// Trait must have a method named `m_name` and it should not have
244+
// type parameters or early-bound regions.
245+
let tcx = fcx.tcx();
246+
let (method_num, method_ty) = trait_method(tcx, trait_def_id, m_name).unwrap();
247+
assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
248+
assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
249+
250+
// Substitute the trait parameters into the method type and
251+
// instantiate late-bound regions to get the actual method type.
252+
let ref bare_fn_ty = method_ty.fty;
253+
let fn_sig = bare_fn_ty.sig.subst(tcx, &trait_ref.substs);
254+
let fn_sig = replace_late_bound_regions_with_fresh_var(fcx.infcx(), span,
255+
fn_sig.binder_id, &fn_sig);
256+
let transformed_self_ty = fn_sig.inputs[0];
257+
let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
258+
sig: fn_sig,
259+
fn_style: bare_fn_ty.fn_style,
260+
abi: bare_fn_ty.abi.clone(),
261+
});
262+
263+
debug!("matched method fty={} obligation={}",
264+
fty.repr(fcx.tcx()),
265+
obligation.repr(fcx.tcx()));
266+
267+
// Register obligations for the parameters. This will include the
268+
// `Self` parameter, which in turn has a bound of the main trait,
269+
// so this also effectively registers `obligation` as well. (We
270+
// used to register `obligation` explicitly, but that resulted in
271+
// double error messages being reported.)
272+
fcx.add_obligations_for_parameters(
273+
traits::ObligationCause::misc(span),
274+
&trait_ref.substs,
275+
&method_ty.generics);
276+
277+
// FIXME(#18653) -- Try to resolve obligations, giving us more
278+
// typing information, which can sometimes be needed to avoid
279+
// pathological region inference failures.
280+
vtable::select_new_fcx_obligations(fcx);
281+
282+
// Insert any adjustments needed (always an autoref of some mutability).
283+
match self_expr {
284+
None => { }
285+
286+
Some(self_expr) => {
287+
debug!("inserting adjustment if needed (self-id = {}, \
288+
base adjustment = {}, explicit self = {})",
289+
self_expr.id, autoderefref, method_ty.explicit_self);
290+
291+
match method_ty.explicit_self {
292+
ty::ByValueExplicitSelfCategory => {
293+
// Trait method is fn(self), no transformation needed.
294+
if !autoderefref.is_identity() {
295+
fcx.write_adjustment(
296+
self_expr.id,
297+
span,
298+
ty::AdjustDerefRef(autoderefref));
299+
}
300+
}
301+
302+
ty::ByReferenceExplicitSelfCategory(..) => {
303+
// Trait method is fn(&self) or fn(&mut self), need an
304+
// autoref. Pull the region etc out of the type of first argument.
305+
match ty::get(transformed_self_ty).sty {
306+
ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => {
307+
let ty::AutoDerefRef { autoderefs, autoref } = autoderefref;
308+
let autoref = autoref.map(|r| box r);
309+
fcx.write_adjustment(
310+
self_expr.id,
311+
span,
312+
ty::AdjustDerefRef(ty::AutoDerefRef {
313+
autoderefs: autoderefs,
314+
autoref: Some(ty::AutoPtr(region, mutbl, autoref))
315+
}));
316+
}
317+
318+
_ => {
319+
fcx.tcx().sess.span_bug(
320+
span,
321+
format!(
322+
"trait method is &self but first arg is: {}",
323+
transformed_self_ty.repr(fcx.tcx())).as_slice());
324+
}
325+
}
326+
}
327+
328+
_ => {
329+
fcx.tcx().sess.span_bug(
330+
span,
331+
format!(
332+
"unexpected explicit self type in operator method: {}",
333+
method_ty.explicit_self).as_slice());
334+
}
335+
}
336+
}
215337
}
338+
339+
let callee = MethodCallee {
340+
origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(),
341+
method_num: method_num}),
342+
ty: fty,
343+
substs: trait_ref.substs.clone()
344+
};
345+
346+
debug!("callee = {}", callee.repr(fcx.tcx()));
347+
348+
Some(callee)
216349
}
217350

218351
pub fn report_error(fcx: &FnCtxt,
@@ -1446,9 +1579,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
14461579
}
14471580
}
14481581

1449-
fn fixup_derefs_on_method_receiver_if_necessary(
1450-
&self,
1451-
method_callee: &MethodCallee) {
1582+
fn fixup_derefs_on_method_receiver_if_necessary(&self,
1583+
method_callee: &MethodCallee) {
14521584
let sig = match ty::get(method_callee.ty).sty {
14531585
ty::ty_bare_fn(ref f) => f.sig.clone(),
14541586
ty::ty_closure(ref f) => f.sig.clone(),
@@ -1485,6 +1617,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
14851617
}
14861618
}
14871619

1620+
debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={}",
1621+
exprs.repr(self.tcx()));
1622+
14881623
// Fix up autoderefs and derefs.
14891624
for (i, expr) in exprs.iter().rev().enumerate() {
14901625
// Count autoderefs.
@@ -1500,6 +1635,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
15001635
Some(_) | None => 0,
15011636
};
15021637

1638+
debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}",
1639+
i, expr.repr(self.tcx()), autoderef_count);
1640+
15031641
if autoderef_count > 0 {
15041642
check::autoderef(self.fcx,
15051643
expr.span,
@@ -1518,24 +1656,59 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
15181656
// Don't retry the first one or we might infinite loop!
15191657
if i != 0 {
15201658
match expr.node {
1521-
ast::ExprIndex(ref base_expr, ref index_expr) => {
1522-
check::try_overloaded_index(
1523-
self.fcx,
1524-
Some(MethodCall::expr(expr.id)),
1525-
*expr,
1659+
ast::ExprIndex(ref base_expr, _) => {
1660+
let mut base_adjustment =
1661+
match self.fcx.inh.adjustments.borrow().find(&base_expr.id) {
1662+
Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(),
1663+
None => ty::AutoDerefRef { autoderefs: 0, autoref: None },
1664+
Some(_) => {
1665+
self.tcx().sess.span_bug(
1666+
base_expr.span,
1667+
"unexpected adjustment type");
1668+
}
1669+
};
1670+
1671+
// If this is an overloaded index, the
1672+
// adjustment will include an extra layer of
1673+
// autoref because the method is an &self/&mut
1674+
// self method. We have to peel it off to get
1675+
// the raw adjustment that `try_index_step`
1676+
// expects. This is annoying and horrible. We
1677+
// ought to recode this routine so it doesn't
1678+
// (ab)use the normal type checking paths.
1679+
base_adjustment.autoref = match base_adjustment.autoref {
1680+
None => { None }
1681+
Some(AutoPtr(_, _, None)) => { None }
1682+
Some(AutoPtr(_, _, Some(box r))) => { Some(r) }
1683+
Some(_) => {
1684+
self.tcx().sess.span_bug(
1685+
base_expr.span,
1686+
"unexpected adjustment autoref");
1687+
}
1688+
};
1689+
1690+
let adjusted_base_ty =
1691+
self.fcx.adjust_expr_ty(
15261692
&**base_expr,
1527-
self.fcx.expr_ty(&**base_expr),
1528-
index_expr,
1529-
PreferMutLvalue);
1693+
Some(&ty::AdjustDerefRef(base_adjustment.clone())));
1694+
1695+
check::try_index_step(
1696+
self.fcx,
1697+
MethodCall::expr(expr.id),
1698+
*expr,
1699+
&**base_expr,
1700+
adjusted_base_ty,
1701+
base_adjustment,
1702+
PreferMutLvalue);
15301703
}
15311704
ast::ExprUnary(ast::UnDeref, ref base_expr) => {
15321705
check::try_overloaded_deref(
1533-
self.fcx,
1534-
expr.span,
1535-
Some(MethodCall::expr(expr.id)),
1536-
Some(&**base_expr),
1537-
self.fcx.expr_ty(&**base_expr),
1538-
PreferMutLvalue);
1706+
self.fcx,
1707+
expr.span,
1708+
Some(MethodCall::expr(expr.id)),
1709+
Some(&**base_expr),
1710+
self.fcx.expr_ty(&**base_expr),
1711+
PreferMutLvalue);
15391712
}
15401713
_ => {}
15411714
}
@@ -1623,15 +1796,25 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
16231796
fn replace_late_bound_regions_with_fresh_var<T>(&self, binder_id: ast::NodeId, value: &T) -> T
16241797
where T : TypeFoldable + Repr
16251798
{
1626-
let (_, value) = replace_late_bound_regions(
1627-
self.fcx.tcx(),
1628-
binder_id,
1629-
value,
1630-
|br| self.fcx.infcx().next_region_var(infer::LateBoundRegion(self.span, br)));
1631-
value
1799+
replace_late_bound_regions_with_fresh_var(self.fcx.infcx(), self.span, binder_id, value)
16321800
}
16331801
}
16341802

1803+
fn replace_late_bound_regions_with_fresh_var<T>(infcx: &infer::InferCtxt,
1804+
span: Span,
1805+
binder_id: ast::NodeId,
1806+
value: &T)
1807+
-> T
1808+
where T : TypeFoldable + Repr
1809+
{
1810+
let (_, value) = replace_late_bound_regions(
1811+
infcx.tcx,
1812+
binder_id,
1813+
value,
1814+
|br| infcx.next_region_var(infer::LateBoundRegion(span, br)));
1815+
value
1816+
}
1817+
16351818
fn trait_method(tcx: &ty::ctxt,
16361819
trait_def_id: ast::DefId,
16371820
method_name: ast::Name)

0 commit comments

Comments
 (0)