Skip to content

Commit 29b31d0

Browse files
committed
Fix ICE that occurs when an associated const is ambiguous.
Also change several error messages to refer to "items" rather than "methods", since associated items that require resolution during type checking are not always methods.
1 parent 4774d5d commit 29b31d0

34 files changed

+182
-147
lines changed

src/librustc_typeck/check/method/mod.rs

+36-36
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ use middle::def;
1616
use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
1717
use middle::subst;
1818
use middle::traits;
19-
use middle::ty::*;
20-
use middle::ty;
19+
use middle::ty::{self, AsPredicate, ToPolyTraitRef};
2120
use middle::infer;
2221
use util::ppaux::Repr;
2322

@@ -39,7 +38,7 @@ pub enum MethodError {
3938
// Did not find an applicable method, but we did find various
4039
// static methods that may apply, as well as a list of
4140
// not-in-scope traits which may work.
42-
NoMatch(Vec<CandidateSource>, Vec<ast::DefId>),
41+
NoMatch(Vec<CandidateSource>, Vec<ast::DefId>, probe::Mode),
4342

4443
// Multiple methods might apply.
4544
Ambiguity(Vec<CandidateSource>),
@@ -62,7 +61,7 @@ type ItemIndex = usize; // just for doc purposes
6261
pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
6362
span: Span,
6463
method_name: ast::Name,
65-
self_ty: Ty<'tcx>,
64+
self_ty: ty::Ty<'tcx>,
6665
call_expr_id: ast::NodeId)
6766
-> bool
6867
{
@@ -92,11 +91,11 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
9291
pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
9392
span: Span,
9493
method_name: ast::Name,
95-
self_ty: Ty<'tcx>,
96-
supplied_method_types: Vec<Ty<'tcx>>,
94+
self_ty: ty::Ty<'tcx>,
95+
supplied_method_types: Vec<ty::Ty<'tcx>>,
9796
call_expr: &'tcx ast::Expr,
9897
self_expr: &'tcx ast::Expr)
99-
-> Result<MethodCallee<'tcx>, MethodError>
98+
-> Result<ty::MethodCallee<'tcx>, MethodError>
10099
{
101100
debug!("lookup(method_name={}, self_ty={}, call_expr={}, self_expr={})",
102101
method_name.repr(fcx.tcx()),
@@ -115,9 +114,9 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
115114
self_expr: Option<&ast::Expr>,
116115
m_name: ast::Name,
117116
trait_def_id: DefId,
118-
self_ty: Ty<'tcx>,
119-
opt_input_types: Option<Vec<Ty<'tcx>>>)
120-
-> Option<MethodCallee<'tcx>>
117+
self_ty: ty::Ty<'tcx>,
118+
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
119+
-> Option<ty::MethodCallee<'tcx>>
121120
{
122121
lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id,
123122
0, false, self_ty, opt_input_types)
@@ -139,9 +138,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
139138
trait_def_id: DefId,
140139
autoderefs: usize,
141140
unsize: bool,
142-
self_ty: Ty<'tcx>,
143-
opt_input_types: Option<Vec<Ty<'tcx>>>)
144-
-> Option<MethodCallee<'tcx>>
141+
self_ty: ty::Ty<'tcx>,
142+
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
143+
-> Option<ty::MethodCallee<'tcx>>
145144
{
146145
debug!("lookup_in_trait_adjusted(self_ty={}, self_expr={}, m_name={}, trait_def_id={})",
147146
self_ty.repr(fcx.tcx()),
@@ -186,7 +185,9 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
186185
// Trait must have a method named `m_name` and it should not have
187186
// type parameters or early-bound regions.
188187
let tcx = fcx.tcx();
189-
let (method_num, method_ty) = trait_method(tcx, trait_def_id, m_name).unwrap();
188+
let (method_num, method_ty) = trait_item(tcx, trait_def_id, m_name)
189+
.and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
190+
.unwrap();
190191
assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
191192
assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
192193

@@ -288,10 +289,10 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
288289
}
289290
}
290291

291-
let callee = MethodCallee {
292-
origin: MethodTypeParam(MethodParam{trait_ref: trait_ref.clone(),
293-
method_num: method_num,
294-
impl_def_id: None}),
292+
let callee = ty::MethodCallee {
293+
origin: ty::MethodTypeParam(ty::MethodParam{trait_ref: trait_ref.clone(),
294+
method_num: method_num,
295+
impl_def_id: None}),
295296
ty: fty,
296297
substs: trait_ref.substs.clone()
297298
};
@@ -304,7 +305,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
304305
pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
305306
span: Span,
306307
method_name: ast::Name,
307-
self_ty: Ty<'tcx>,
308+
self_ty: ty::Ty<'tcx>,
308309
expr_id: ast::NodeId)
309310
-> Result<(def::Def, LastPrivate), MethodError>
310311
{
@@ -322,41 +323,40 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
322323
_ => def::FromTrait(pick.item.container().id())
323324
};
324325
let def_result = match pick.item {
325-
ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
326-
ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance),
327-
ImplOrTraitItem::TypeTraitItem(..) => {
326+
ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
327+
ty::ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance),
328+
ty::ImplOrTraitItem::TypeTraitItem(..) => {
328329
fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
329330
}
330331
};
331332
Ok((def_result, lp))
332333
}
333334

334335

335-
/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
336-
/// index (or `None`, if no such method).
337-
fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
338-
trait_def_id: ast::DefId,
339-
method_name: ast::Name)
340-
-> Option<(usize, Rc<ty::Method<'tcx>>)>
336+
/// Find item with name `item_name` defined in `trait_def_id` and return it, along with its
337+
/// index (or `None`, if no such item).
338+
fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
339+
trait_def_id: ast::DefId,
340+
item_name: ast::Name)
341+
-> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
341342
{
342343
let trait_items = ty::trait_items(tcx, trait_def_id);
343344
trait_items
344345
.iter()
345346
.enumerate()
346-
.find(|&(_, ref item)| item.name() == method_name)
347-
.and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
347+
.find(|&(_, ref item)| item.name() == item_name)
348+
.map(|(num, item)| (num, (*item).clone()))
348349
}
349350

350-
fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
351-
impl_def_id: ast::DefId,
352-
method_name: ast::Name)
353-
-> Option<Rc<ty::Method<'tcx>>>
351+
fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
352+
impl_def_id: ast::DefId,
353+
item_name: ast::Name)
354+
-> Option<ty::ImplOrTraitItem<'tcx>>
354355
{
355356
let impl_items = tcx.impl_items.borrow();
356357
let impl_items = impl_items.get(&impl_def_id).unwrap();
357358
impl_items
358359
.iter()
359360
.map(|&did| ty::impl_or_trait_item(tcx, did.def_id()))
360-
.find(|m| m.name() == method_name)
361-
.and_then(|item| item.as_opt_method())
361+
.find(|m| m.name() == item_name)
362362
}

src/librustc_typeck/check/method/probe.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
136136
let steps = if mode == Mode::MethodCall {
137137
match create_steps(fcx, span, self_ty) {
138138
Some(steps) => steps,
139-
None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())),
139+
None => return Err(MethodError::NoMatch(Vec::new(), Vec::new(), mode)),
140140
}
141141
} else {
142142
vec![CandidateStep {
@@ -866,7 +866,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
866866
}
867867
}
868868
}).collect(),
869-
Some(Err(MethodError::NoMatch(_, others))) => {
869+
Some(Err(MethodError::NoMatch(_, others, _))) => {
870870
assert!(others.is_empty());
871871
vec![]
872872
}
@@ -877,7 +877,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
877877
None => vec![],
878878
};
879879

880-
Err(MethodError::NoMatch(static_candidates, out_of_scope_traits))
880+
Err(MethodError::NoMatch(static_candidates, out_of_scope_traits, self.mode))
881881
}
882882

883883
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {

src/librustc_typeck/check/method/suggest.rs

+37-34
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! Give useful errors and suggestions to users when a method can't be
11+
//! Give useful errors and suggestions to users when an item can't be
1212
//! found or is otherwise invalid.
1313
1414
use CrateCtxt;
@@ -27,12 +27,13 @@ use syntax::print::pprust;
2727
use std::cell;
2828
use std::cmp::Ordering;
2929

30-
use super::{MethodError, CandidateSource, impl_method, trait_method};
30+
use super::{MethodError, CandidateSource, impl_item, trait_item};
31+
use super::probe::Mode;
3132

3233
pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3334
span: Span,
3435
rcvr_ty: Ty<'tcx>,
35-
method_name: ast::Name,
36+
item_name: ast::Name,
3637
rcvr_expr: Option<&ast::Expr>,
3738
error: MethodError)
3839
{
@@ -42,28 +43,30 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
4243
}
4344

4445
match error {
45-
MethodError::NoMatch(static_sources, out_of_scope_traits) => {
46+
MethodError::NoMatch(static_sources, out_of_scope_traits, mode) => {
4647
let cx = fcx.tcx();
47-
let method_ustring = method_name.user_string(cx);
48+
let item_ustring = item_name.user_string(cx);
4849

4950
fcx.type_error_message(
5051
span,
5152
|actual| {
52-
format!("type `{}` does not implement any \
53-
method in scope named `{}`",
54-
actual,
55-
method_ustring)
53+
format!("no {} named `{}` found for type `{}` \
54+
in the current scope",
55+
if mode == Mode::MethodCall { "method" }
56+
else { "associated item" },
57+
item_ustring,
58+
actual)
5659
},
5760
rcvr_ty,
5861
None);
5962

60-
// If the method has the name of a field, give a help note
63+
// If the item has the name of a field, give a help note
6164
if let (&ty::ty_struct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) {
6265
let fields = ty::lookup_struct_fields(cx, did);
63-
if fields.iter().any(|f| f.name == method_name) {
66+
if fields.iter().any(|f| f.name == item_name) {
6467
cx.sess.span_note(span,
6568
&format!("use `(s.{0})(...)` if you meant to call the \
66-
function stored in the `{0}` field", method_ustring));
69+
function stored in the `{0}` field", item_ustring));
6770
}
6871
}
6972

@@ -72,25 +75,25 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
7275
span,
7376
"found defined static methods, maybe a `self` is missing?");
7477

75-
report_candidates(fcx, span, method_name, static_sources);
78+
report_candidates(fcx, span, item_name, static_sources);
7679
}
7780

78-
suggest_traits_to_import(fcx, span, rcvr_ty, method_name,
81+
suggest_traits_to_import(fcx, span, rcvr_ty, item_name,
7982
rcvr_expr, out_of_scope_traits)
8083
}
8184

8285
MethodError::Ambiguity(sources) => {
8386
span_err!(fcx.sess(), span, E0034,
84-
"multiple applicable methods in scope");
87+
"multiple applicable items in scope");
8588

86-
report_candidates(fcx, span, method_name, sources);
89+
report_candidates(fcx, span, item_name, sources);
8790
}
8891

8992
MethodError::ClosureAmbiguity(trait_def_id) => {
9093
let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
9194
invoked on this closure as we have not yet inferred what \
9295
kind of closure it is",
93-
method_name.user_string(fcx.tcx()),
96+
item_name.user_string(fcx.tcx()),
9497
ty::item_path_str(fcx.tcx(), trait_def_id));
9598
let msg = if let Some(callee) = rcvr_expr {
9699
format!("{}; use overloaded call notation instead (e.g., `{}()`)",
@@ -104,19 +107,19 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
104107

105108
fn report_candidates(fcx: &FnCtxt,
106109
span: Span,
107-
method_name: ast::Name,
110+
item_name: ast::Name,
108111
mut sources: Vec<CandidateSource>) {
109112
sources.sort();
110113
sources.dedup();
111114

112115
for (idx, source) in sources.iter().enumerate() {
113116
match *source {
114117
CandidateSource::ImplSource(impl_did) => {
115-
// Provide the best span we can. Use the method, if local to crate, else
116-
// the impl, if local to crate (method may be defaulted), else the call site.
117-
let method = impl_method(fcx.tcx(), impl_did, method_name).unwrap();
118+
// Provide the best span we can. Use the item, if local to crate, else
119+
// the impl, if local to crate (item may be defaulted), else the call site.
120+
let item = impl_item(fcx.tcx(), impl_did, item_name).unwrap();
118121
let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
119-
let method_span = fcx.tcx().map.def_id_span(method.def_id, impl_span);
122+
let item_span = fcx.tcx().map.def_id_span(item.def_id(), impl_span);
120123

121124
let impl_ty = check::impl_self_ty(fcx, span, impl_did).ty;
122125

@@ -127,16 +130,16 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
127130
trait_ref.def_id)),
128131
};
129132

130-
span_note!(fcx.sess(), method_span,
133+
span_note!(fcx.sess(), item_span,
131134
"candidate #{} is defined in an impl{} for the type `{}`",
132135
idx + 1,
133136
insertion,
134137
impl_ty.user_string(fcx.tcx()));
135138
}
136139
CandidateSource::TraitSource(trait_did) => {
137-
let (_, method) = trait_method(fcx.tcx(), trait_did, method_name).unwrap();
138-
let method_span = fcx.tcx().map.def_id_span(method.def_id, span);
139-
span_note!(fcx.sess(), method_span,
140+
let (_, item) = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
141+
let item_span = fcx.tcx().map.def_id_span(item.def_id(), span);
142+
span_note!(fcx.sess(), item_span,
140143
"candidate #{} is defined in the trait `{}`",
141144
idx + 1,
142145
ty::item_path_str(fcx.tcx(), trait_did));
@@ -152,19 +155,19 @@ pub type AllTraitsVec = Vec<TraitInfo>;
152155
fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
153156
span: Span,
154157
rcvr_ty: Ty<'tcx>,
155-
method_name: ast::Name,
158+
item_name: ast::Name,
156159
rcvr_expr: Option<&ast::Expr>,
157160
valid_out_of_scope_traits: Vec<ast::DefId>)
158161
{
159162
let tcx = fcx.tcx();
160-
let method_ustring = method_name.user_string(tcx);
163+
let item_ustring = item_name.user_string(tcx);
161164

162165
if !valid_out_of_scope_traits.is_empty() {
163166
let mut candidates = valid_out_of_scope_traits;
164167
candidates.sort();
165168
candidates.dedup();
166169
let msg = format!(
167-
"methods from traits can only be called if the trait is in scope; \
170+
"items from traits can only be used if the trait is in scope; \
168171
the following {traits_are} implemented but not in scope, \
169172
perhaps add a `use` for {one_of_them}:",
170173
traits_are = if candidates.len() == 1 {"trait is"} else {"traits are"},
@@ -185,7 +188,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
185188
let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty, rcvr_expr);
186189

187190
// there's no implemented traits, so lets suggest some traits to
188-
// implement, by finding ones that have the method name, and are
191+
// implement, by finding ones that have the item name, and are
189192
// legal to implement.
190193
let mut candidates = all_traits(fcx.ccx)
191194
.filter(|info| {
@@ -196,7 +199,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
196199
// implementing a trait would be legal but is rejected
197200
// here).
198201
(type_is_local || ast_util::is_local(info.def_id))
199-
&& trait_method(tcx, info.def_id, method_name).is_some()
202+
&& trait_item(tcx, info.def_id, item_name).is_some()
200203
})
201204
.collect::<Vec<_>>();
202205

@@ -209,12 +212,12 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
209212
// of a type parameter: suggest adding a trait bound rather
210213
// than implementing.
211214
let msg = format!(
212-
"methods from traits can only be called if the trait is implemented and in scope; \
213-
the following {traits_define} a method `{name}`, \
215+
"items from traits can only be used if the trait is implemented and in scope; \
216+
the following {traits_define} an item `{name}`, \
214217
perhaps you need to implement {one_of_them}:",
215218
traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"},
216219
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
217-
name = method_ustring);
220+
name = item_ustring);
218221

219222
fcx.sess().fileline_help(span, &msg[..]);
220223

0 commit comments

Comments
 (0)