Skip to content

Commit 870aea2

Browse files
committed
Do not ICE when e.g. call_mut() is called on a closure whose kind is not yet known.
1 parent a9c3841 commit 870aea2

File tree

5 files changed

+77
-28
lines changed

5 files changed

+77
-28
lines changed

src/librustc_typeck/check/method/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ pub enum MethodError {
4444

4545
// Multiple methods might apply.
4646
Ambiguity(Vec<CandidateSource>),
47+
48+
// Using a `Fn`/`FnMut`/etc method on a raw closure type before we have inferred its kind.
49+
ClosureAmbiguity(/* DefId of fn trait */ ast::DefId),
4750
}
4851

4952
// A pared down enum describing just the places from which a method
@@ -65,9 +68,10 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
6568
-> bool
6669
{
6770
match probe::probe(fcx, span, method_name, self_ty, call_expr_id) {
68-
Ok(_) => true,
69-
Err(NoMatch(_, _)) => false,
70-
Err(Ambiguity(_)) => true,
71+
Ok(..) => true,
72+
Err(NoMatch(..)) => false,
73+
Err(Ambiguity(..)) => true,
74+
Err(ClosureAmbiguity(..)) => true,
7175
}
7276
}
7377

src/librustc_typeck/check/method/probe.rs

+36-24
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-
use super::{MethodError,Ambiguity,NoMatch};
11+
use super::{MethodError};
1212
use super::MethodIndex;
1313
use super::{CandidateSource,ImplSource,TraitSource};
1414
use super::suggest;
@@ -129,7 +129,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
129129
// take place in the `fcx.infcx().probe` below.
130130
let steps = match create_steps(fcx, span, self_ty) {
131131
Some(steps) => steps,
132-
None => return Err(NoMatch(Vec::new(), Vec::new())),
132+
None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())),
133133
};
134134

135135
// Create a list of simplified self types, if we can.
@@ -158,7 +158,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
158158
let (steps, opt_simplified_steps) = dummy.take().unwrap();
159159
let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps);
160160
probe_cx.assemble_inherent_candidates();
161-
probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id);
161+
try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id));
162162
probe_cx.pick()
163163
})
164164
}
@@ -444,29 +444,34 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
444444

445445
fn assemble_extension_candidates_for_traits_in_scope(&mut self,
446446
expr_id: ast::NodeId)
447+
-> Result<(),MethodError>
447448
{
448449
let mut duplicates = HashSet::new();
449450
let opt_applicable_traits = self.fcx.ccx.trait_map.get(&expr_id);
450451
for applicable_traits in opt_applicable_traits.into_iter() {
451452
for &trait_did in applicable_traits.iter() {
452453
if duplicates.insert(trait_did) {
453-
self.assemble_extension_candidates_for_trait(trait_did);
454+
try!(self.assemble_extension_candidates_for_trait(trait_did));
454455
}
455456
}
456457
}
458+
Ok(())
457459
}
458460

459-
fn assemble_extension_candidates_for_all_traits(&mut self) {
461+
fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(),MethodError> {
460462
let mut duplicates = HashSet::new();
461463
for trait_info in suggest::all_traits(self.fcx.ccx) {
462464
if duplicates.insert(trait_info.def_id) {
463-
self.assemble_extension_candidates_for_trait(trait_info.def_id)
465+
try!(self.assemble_extension_candidates_for_trait(trait_info.def_id));
464466
}
465467
}
468+
Ok(())
466469
}
467470

468471
fn assemble_extension_candidates_for_trait(&mut self,
469-
trait_def_id: ast::DefId) {
472+
trait_def_id: ast::DefId)
473+
-> Result<(),MethodError>
474+
{
470475
debug!("assemble_extension_candidates_for_trait(trait_def_id={})",
471476
trait_def_id.repr(self.tcx()));
472477

@@ -478,26 +483,27 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
478483
.position(|item| item.name() == self.method_name);
479484
let matching_index = match matching_index {
480485
Some(i) => i,
481-
None => { return; }
486+
None => { return Ok(()); }
482487
};
483488
let method = match (&*trait_items)[matching_index].as_opt_method() {
484489
Some(m) => m,
485-
None => { return; }
490+
None => { return Ok(()); }
486491
};
487492

488493
// Check whether `trait_def_id` defines a method with suitable name:
489494
if !self.has_applicable_self(&*method) {
490495
debug!("method has inapplicable self");
491-
return self.record_static_candidate(TraitSource(trait_def_id));
496+
self.record_static_candidate(TraitSource(trait_def_id));
497+
return Ok(());
492498
}
493499

494500
self.assemble_extension_candidates_for_trait_impls(trait_def_id,
495501
method.clone(),
496502
matching_index);
497503

498-
self.assemble_closure_candidates(trait_def_id,
499-
method.clone(),
500-
matching_index);
504+
try!(self.assemble_closure_candidates(trait_def_id,
505+
method.clone(),
506+
matching_index));
501507

502508
self.assemble_projection_candidates(trait_def_id,
503509
method.clone(),
@@ -506,6 +512,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
506512
self.assemble_where_clause_candidates(trait_def_id,
507513
method,
508514
matching_index);
515+
516+
Ok(())
509517
}
510518

511519
fn assemble_extension_candidates_for_trait_impls(&mut self,
@@ -576,6 +584,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
576584
trait_def_id: ast::DefId,
577585
method_ty: Rc<ty::Method<'tcx>>,
578586
method_index: uint)
587+
-> Result<(),MethodError>
579588
{
580589
// Check if this is one of the Fn,FnMut,FnOnce traits.
581590
let tcx = self.tcx();
@@ -586,7 +595,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
586595
} else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
587596
ty::FnOnceClosureKind
588597
} else {
589-
return;
598+
return Ok(());
590599
};
591600

592601
// Check if there is an unboxed-closure self-type in the list of receivers.
@@ -602,10 +611,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
602611
let closure_kind = match closure_kinds.get(&closure_def_id) {
603612
Some(&k) => k,
604613
None => {
605-
self.tcx().sess.span_bug(
606-
self.span,
607-
&format!("No entry for closure: {}",
608-
closure_def_id.repr(self.tcx()))[]);
614+
return Err(MethodError::ClosureAmbiguity(trait_def_id));
609615
}
610616
};
611617

@@ -630,6 +636,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
630636
kind: ClosureCandidate(trait_def_id, method_index)
631637
});
632638
}
639+
640+
Ok(())
633641
}
634642

635643
fn assemble_projection_candidates(&mut self,
@@ -735,11 +743,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
735743
let span = self.span;
736744
let tcx = self.tcx();
737745

738-
self.assemble_extension_candidates_for_all_traits();
746+
try!(self.assemble_extension_candidates_for_all_traits());
739747

740748
let out_of_scope_traits = match self.pick_core() {
741749
Some(Ok(p)) => vec![p.method_ty.container.id()],
742-
Some(Err(Ambiguity(v))) => v.into_iter().map(|source| {
750+
Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| {
743751
match source {
744752
TraitSource(id) => id,
745753
ImplSource(impl_id) => {
@@ -752,14 +760,18 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
752760
}
753761
}
754762
}).collect(),
755-
Some(Err(NoMatch(_, others))) => {
763+
Some(Err(MethodError::NoMatch(_, others))) => {
756764
assert!(others.is_empty());
757765
vec![]
758766
}
767+
Some(Err(MethodError::ClosureAmbiguity(..))) => {
768+
// this error only occurs when assembling candidates
769+
tcx.sess.span_bug(span, "encountered ClosureAmbiguity from pick_core");
770+
}
759771
None => vec![],
760772
};
761-
;
762-
Err(NoMatch(static_candidates, out_of_scope_traits))
773+
774+
Err(MethodError::NoMatch(static_candidates, out_of_scope_traits))
763775
}
764776

765777
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
@@ -895,7 +907,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
895907

896908
if applicable_candidates.len() > 1 {
897909
let sources = probes.iter().map(|p| p.to_source()).collect();
898-
return Some(Err(Ambiguity(sources)));
910+
return Some(Err(MethodError::Ambiguity(sources)));
899911
}
900912

901913
applicable_candidates.pop().map(|probe| {

src/librustc_typeck/check/method/suggest.rs

+14
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use util::ppaux::UserString;
2222

2323
use syntax::{ast, ast_util};
2424
use syntax::codemap::Span;
25+
use syntax::print::pprust;
2526

2627
use std::cell;
2728
use std::cmp::Ordering;
@@ -32,6 +33,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3233
span: Span,
3334
rcvr_ty: Ty<'tcx>,
3435
method_name: ast::Name,
36+
callee_expr: &ast::Expr,
3537
error: MethodError)
3638
{
3739
match error {
@@ -84,6 +86,18 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
8486

8587
report_candidates(fcx, span, method_name, sources);
8688
}
89+
90+
MethodError::ClosureAmbiguity(trait_def_id) => {
91+
fcx.sess().span_err(
92+
span,
93+
&*format!("the `{}` method from the `{}` trait cannot be explicitly \
94+
invoked on this closure as we have not yet inferred what \
95+
kind of closure it is; use overloaded call notation instead \
96+
(e.g., `{}()`)",
97+
method_name.user_string(fcx.tcx()),
98+
ty::item_path_str(fcx.tcx(), trait_def_id),
99+
pprust::expr_to_string(callee_expr)));
100+
}
87101
}
88102

89103
fn report_candidates(fcx: &FnCtxt,

src/librustc_typeck/check/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2695,7 +2695,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
26952695
method_ty
26962696
}
26972697
Err(error) => {
2698-
method::report_error(fcx, method_name.span, expr_t, method_name.node.name, error);
2698+
method::report_error(fcx, method_name.span, expr_t,
2699+
method_name.node.name, rcvr, error);
26992700
fcx.write_error(expr.id);
27002701
fcx.tcx().types.err
27012702
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
11+
#![feature(unboxed_closures)]
12+
13+
fn main() {
14+
let mut zero = || {};
15+
let () = zero.call_mut(());
16+
//~^ ERROR we have not yet inferred what kind of closure it is
17+
}
18+

0 commit comments

Comments
 (0)