]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/check/method/mod.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_typeck / check / method / mod.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
c34b1796 11//! Method lookup: the secret sauce of Rust. See `README.md`.
1a4d82fc
JJ
12
13use astconv::AstConv;
c34b1796 14use check::FnCtxt;
54a0048b
SL
15use hir::def::Def;
16use hir::def_id::DefId;
17use rustc::ty::subst;
18use rustc::traits;
19use rustc::ty::{self, TyCtxt, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
20use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr};
21use rustc::infer;
1a4d82fc 22
1a4d82fc
JJ
23use syntax::ast;
24use syntax::codemap::Span;
25
54a0048b 26use rustc::hir;
e9174d1e 27
1a4d82fc
JJ
28pub use self::MethodError::*;
29pub use self::CandidateSource::*;
30
85aaf69f
SL
31pub use self::suggest::{report_error, AllTraitsVec};
32
1a4d82fc 33mod confirm;
1a4d82fc 34mod probe;
85aaf69f 35mod suggest;
1a4d82fc 36
62682a34
SL
37pub enum MethodError<'tcx> {
38 // Did not find an applicable method, but we did find various near-misses that may work.
39 NoMatch(NoMatchData<'tcx>),
1a4d82fc
JJ
40
41 // Multiple methods might apply.
42 Ambiguity(Vec<CandidateSource>),
85aaf69f
SL
43
44 // Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind.
e9174d1e 45 ClosureAmbiguity(/* DefId of fn trait */ DefId),
54a0048b
SL
46
47 // Found an applicable method, but it is not visible.
48 PrivateMatch(Def),
1a4d82fc
JJ
49}
50
62682a34
SL
51// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
52// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
53pub struct NoMatchData<'tcx> {
54 pub static_candidates: Vec<CandidateSource>,
55 pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
e9174d1e 56 pub out_of_scope_traits: Vec<DefId>,
62682a34
SL
57 pub mode: probe::Mode
58}
59
60impl<'tcx> NoMatchData<'tcx> {
61 pub fn new(static_candidates: Vec<CandidateSource>,
62 unsatisfied_predicates: Vec<TraitRef<'tcx>>,
e9174d1e 63 out_of_scope_traits: Vec<DefId>,
62682a34
SL
64 mode: probe::Mode) -> Self {
65 NoMatchData {
66 static_candidates: static_candidates,
67 unsatisfied_predicates: unsatisfied_predicates,
68 out_of_scope_traits: out_of_scope_traits,
69 mode: mode
70 }
71 }
72}
73
1a4d82fc
JJ
74// A pared down enum describing just the places from which a method
75// candidate can arise. Used for error reporting only.
62682a34 76#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
1a4d82fc 77pub enum CandidateSource {
e9174d1e
SL
78 ImplSource(DefId),
79 TraitSource(/* trait id */ DefId),
1a4d82fc
JJ
80}
81
1a4d82fc
JJ
82/// Determines whether the type `self_ty` supports a method name `method_name` or not.
83pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
84 span: Span,
85 method_name: ast::Name,
d9579d0f 86 self_ty: ty::Ty<'tcx>,
1a4d82fc
JJ
87 call_expr_id: ast::NodeId)
88 -> bool
89{
c34b1796
AL
90 let mode = probe::Mode::MethodCall;
91 match probe::probe(fcx, span, mode, method_name, self_ty, call_expr_id) {
85aaf69f
SL
92 Ok(..) => true,
93 Err(NoMatch(..)) => false,
94 Err(Ambiguity(..)) => true,
95 Err(ClosureAmbiguity(..)) => true,
54a0048b 96 Err(PrivateMatch(..)) => true,
1a4d82fc
JJ
97 }
98}
99
100/// Performs method lookup. If lookup is successful, it will return the callee and store an
101/// appropriate adjustment for the self-expr. In some cases it may report an error (e.g., invoking
102/// the `drop` method).
103///
104/// # Arguments
105///
106/// Given a method call like `foo.bar::<T1,...Tn>(...)`:
107///
108/// * `fcx`: the surrounding `FnCtxt` (!)
109/// * `span`: the span for the method call
110/// * `method_name`: the name of the method being called (`bar`)
111/// * `self_ty`: the (unadjusted) type of the self expression (`foo`)
112/// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`)
113/// * `self_expr`: the self expression (`foo`)
114pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
115 span: Span,
116 method_name: ast::Name,
d9579d0f
AL
117 self_ty: ty::Ty<'tcx>,
118 supplied_method_types: Vec<ty::Ty<'tcx>>,
e9174d1e
SL
119 call_expr: &'tcx hir::Expr,
120 self_expr: &'tcx hir::Expr)
62682a34 121 -> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
1a4d82fc 122{
62682a34
SL
123 debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
124 method_name,
125 self_ty,
126 call_expr,
127 self_expr);
1a4d82fc 128
c34b1796 129 let mode = probe::Mode::MethodCall;
1a4d82fc 130 let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
54a0048b 131 let pick = probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id)?;
1a4d82fc
JJ
132 Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
133}
134
135pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
136 span: Span,
e9174d1e 137 self_expr: Option<&hir::Expr>,
1a4d82fc
JJ
138 m_name: ast::Name,
139 trait_def_id: DefId,
d9579d0f
AL
140 self_ty: ty::Ty<'tcx>,
141 opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
142 -> Option<ty::MethodCallee<'tcx>>
1a4d82fc
JJ
143{
144 lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
9346a6ac 145 0, false, self_ty, opt_input_types)
1a4d82fc
JJ
146}
147
148/// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of
149/// what the normal probe/confirm path does. In particular, it doesn't really do any probing: it
150/// simply constructs an obligation for a particular trait with the given self-type and checks
151/// whether that trait is implemented.
152///
153/// FIXME(#18741) -- It seems likely that we can consolidate some of this code with the other
154/// method-lookup code. In particular, autoderef on index is basically identical to autoderef with
155/// normal probes, except that the test also looks for built-in indexing. Also, the second half of
156/// this method is basically the same as confirmation.
157pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
158 span: Span,
e9174d1e 159 self_expr: Option<&hir::Expr>,
1a4d82fc
JJ
160 m_name: ast::Name,
161 trait_def_id: DefId,
9346a6ac
AL
162 autoderefs: usize,
163 unsize: bool,
d9579d0f
AL
164 self_ty: ty::Ty<'tcx>,
165 opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
166 -> Option<ty::MethodCallee<'tcx>>
1a4d82fc 167{
62682a34
SL
168 debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, m_name={}, trait_def_id={:?})",
169 self_ty,
170 self_expr,
171 m_name,
172 trait_def_id);
1a4d82fc 173
c1a9b12d
SL
174 let trait_def = fcx.tcx().lookup_trait_def(trait_def_id);
175
176 let type_parameter_defs = trait_def.generics.types.get_slice(subst::TypeSpace);
177 let expected_number_of_input_types = type_parameter_defs.len();
178
179 assert_eq!(trait_def.generics.types.len(subst::FnSpace), 0);
180 assert!(trait_def.generics.regions.is_empty());
1a4d82fc 181
c1a9b12d
SL
182 // Construct a trait-reference `self_ty : Trait<input_tys>`
183 let mut substs = subst::Substs::new_trait(Vec::new(), Vec::new(), self_ty);
184
185 match opt_input_types {
1a4d82fc
JJ
186 Some(input_types) => {
187 assert_eq!(expected_number_of_input_types, input_types.len());
c1a9b12d 188 substs.types.replace(subst::ParamSpace::TypeSpace, input_types);
1a4d82fc
JJ
189 }
190
191 None => {
c1a9b12d
SL
192 fcx.inh.infcx.type_vars_for_defs(
193 span,
194 subst::ParamSpace::TypeSpace,
195 &mut substs,
196 type_parameter_defs);
1a4d82fc 197 }
c1a9b12d 198 }
1a4d82fc 199
d9579d0f 200 let trait_ref = ty::TraitRef::new(trait_def_id, fcx.tcx().mk_substs(substs));
1a4d82fc
JJ
201
202 // Construct an obligation
203 let poly_trait_ref = trait_ref.to_poly_trait_ref();
204 let obligation = traits::Obligation::misc(span,
205 fcx.body_id,
c1a9b12d 206 poly_trait_ref.to_predicate());
1a4d82fc
JJ
207
208 // Now we want to know if this can be matched
c1a9b12d 209 let mut selcx = traits::SelectionContext::new(fcx.infcx());
1a4d82fc
JJ
210 if !selcx.evaluate_obligation(&obligation) {
211 debug!("--> Cannot match obligation");
212 return None; // Cannot be matched, no such method resolution is possible.
213 }
214
215 // Trait must have a method named `m_name` and it should not have
216 // type parameters or early-bound regions.
217 let tcx = fcx.tcx();
c1a9b12d
SL
218 let method_item = trait_item(tcx, trait_def_id, m_name).unwrap();
219 let method_ty = method_item.as_opt_method().unwrap();
1a4d82fc
JJ
220 assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
221 assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
222
c1a9b12d
SL
223 debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}",
224 method_item, method_ty);
1a4d82fc
JJ
225
226 // Instantiate late-bound regions and substitute the trait
227 // parameters into the method type to get the actual method type.
228 //
229 // NB: Instantiate late-bound regions first so that
230 // `instantiate_type_scheme` can normalize associated types that
231 // may reference those regions.
232 let fn_sig = fcx.infcx().replace_late_bound_regions_with_fresh_var(span,
233 infer::FnCall,
234 &method_ty.fty.sig).0;
235 let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
236 let transformed_self_ty = fn_sig.inputs[0];
54a0048b
SL
237 let def_id = method_item.def_id();
238 let fty = tcx.mk_fn_def(def_id, trait_ref.substs, ty::BareFnTy {
1a4d82fc
JJ
239 sig: ty::Binder(fn_sig),
240 unsafety: method_ty.fty.unsafety,
241 abi: method_ty.fty.abi.clone(),
54a0048b 242 });
1a4d82fc 243
62682a34
SL
244 debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
245 fty,
246 obligation);
1a4d82fc
JJ
247
248 // Register obligations for the parameters. This will include the
249 // `Self` parameter, which in turn has a bound of the main trait,
250 // so this also effectively registers `obligation` as well. (We
251 // used to register `obligation` explicitly, but that resulted in
252 // double error messages being reported.)
253 //
254 // Note that as the method comes from a trait, it should not have
255 // any late-bound regions appearing in its bounds.
85aaf69f 256 let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
1a4d82fc
JJ
257 assert!(!method_bounds.has_escaping_regions());
258 fcx.add_obligations_for_parameters(
259 traits::ObligationCause::misc(span, fcx.body_id),
260 &method_bounds);
261
b039eaaf
SL
262 // Also register an obligation for the method type being well-formed.
263 fcx.register_wf_obligation(fty, span, traits::MiscObligation);
264
1a4d82fc
JJ
265 // FIXME(#18653) -- Try to resolve obligations, giving us more
266 // typing information, which can sometimes be needed to avoid
267 // pathological region inference failures.
7453a54e 268 fcx.select_obligations_where_possible();
1a4d82fc
JJ
269
270 // Insert any adjustments needed (always an autoref of some mutability).
271 match self_expr {
272 None => { }
273
274 Some(self_expr) => {
275 debug!("lookup_in_trait_adjusted: inserting adjustment if needed \
9346a6ac
AL
276 (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})",
277 self_expr.id, autoderefs, unsize,
278 method_ty.explicit_self);
1a4d82fc
JJ
279
280 match method_ty.explicit_self {
9cc50fc6 281 ty::ExplicitSelfCategory::ByValue => {
1a4d82fc 282 // Trait method is fn(self), no transformation needed.
9346a6ac
AL
283 assert!(!unsize);
284 fcx.write_autoderef_adjustment(self_expr.id, autoderefs);
1a4d82fc
JJ
285 }
286
9cc50fc6 287 ty::ExplicitSelfCategory::ByReference(..) => {
1a4d82fc
JJ
288 // Trait method is fn(&self) or fn(&mut self), need an
289 // autoref. Pull the region etc out of the type of first argument.
290 match transformed_self_ty.sty {
c1a9b12d 291 ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => {
9346a6ac 292 fcx.write_adjustment(self_expr.id,
e9174d1e 293 AdjustDerefRef(AutoDerefRef {
1a4d82fc 294 autoderefs: autoderefs,
e9174d1e 295 autoref: Some(AutoPtr(region, mutbl)),
9346a6ac
AL
296 unsize: if unsize {
297 Some(transformed_self_ty)
298 } else {
299 None
300 }
1a4d82fc
JJ
301 }));
302 }
303
304 _ => {
54a0048b 305 span_bug!(
1a4d82fc 306 span,
54a0048b
SL
307 "trait method is &self but first arg is: {}",
308 transformed_self_ty);
1a4d82fc
JJ
309 }
310 }
311 }
312
313 _ => {
54a0048b 314 span_bug!(
1a4d82fc 315 span,
54a0048b
SL
316 "unexpected explicit self type in operator method: {:?}",
317 method_ty.explicit_self);
1a4d82fc
JJ
318 }
319 }
320 }
321 }
322
d9579d0f 323 let callee = ty::MethodCallee {
54a0048b 324 def_id: def_id,
1a4d82fc 325 ty: fty,
c1a9b12d 326 substs: trait_ref.substs
1a4d82fc
JJ
327 };
328
62682a34 329 debug!("callee = {:?}", callee);
1a4d82fc
JJ
330
331 Some(callee)
332}
333
c34b1796
AL
334pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
335 span: Span,
336 method_name: ast::Name,
d9579d0f 337 self_ty: ty::Ty<'tcx>,
c34b1796 338 expr_id: ast::NodeId)
54a0048b 339 -> Result<Def, MethodError<'tcx>>
c34b1796
AL
340{
341 let mode = probe::Mode::Path;
54a0048b
SL
342 let pick = probe::probe(fcx, span, mode, method_name, self_ty, expr_id)?;
343 let def = pick.item.def();
344
c1a9b12d 345 if let probe::InherentImplPick = pick.kind {
54a0048b
SL
346 if !pick.item.vis().is_accessible_from(fcx.body_id, &fcx.tcx().map) {
347 let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str());
348 fcx.tcx().sess.span_err(span, &msg);
c34b1796 349 }
c1a9b12d 350 }
54a0048b 351 Ok(def)
c34b1796
AL
352}
353
c1a9b12d
SL
354/// Find item with name `item_name` defined in `trait_def_id`
355/// and return it, or `None`, if no such item.
54a0048b 356fn trait_item<'tcx>(tcx: &TyCtxt<'tcx>,
e9174d1e 357 trait_def_id: DefId,
d9579d0f 358 item_name: ast::Name)
c1a9b12d 359 -> Option<ty::ImplOrTraitItem<'tcx>>
1a4d82fc 360{
c1a9b12d
SL
361 let trait_items = tcx.trait_items(trait_def_id);
362 trait_items.iter()
363 .find(|item| item.name() == item_name)
364 .cloned()
1a4d82fc
JJ
365}
366
54a0048b 367fn impl_item<'tcx>(tcx: &TyCtxt<'tcx>,
e9174d1e 368 impl_def_id: DefId,
d9579d0f
AL
369 item_name: ast::Name)
370 -> Option<ty::ImplOrTraitItem<'tcx>>
1a4d82fc
JJ
371{
372 let impl_items = tcx.impl_items.borrow();
373 let impl_items = impl_items.get(&impl_def_id).unwrap();
374 impl_items
375 .iter()
c1a9b12d 376 .map(|&did| tcx.impl_or_trait_item(did.def_id()))
d9579d0f 377 .find(|m| m.name() == item_name)
1a4d82fc 378}