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