Skip to content

Commit cffaf0e

Browse files
committed
Auto merge of #26435 - gsingh93:master, r=nikomatsakis
When a method exists in an impl but can not be used due to missing trait bounds for the type parameters, we should inform the user which trait bounds are missing. For example, this code ``` // Note this is missing a Debug impl struct Foo; fn main() { let a: Result<(), Foo> = Ok(()); a.unwrap() } ``` Now gives the following error: ``` /home/gulshan/tmp/tmp.rs:6:7: 6:15 error: no method named `unwrap` found for type `core::result::Result<(), Foo>` in the current scope /home/gulshan/tmp/tmp.rs:6 a.unwrap() ^~~~~~~~ /home/gulshan/tmp/tmp.rs:6:7: 6:15 note: The method `unwrap` exists but the following trait bounds were not satisfied: `Foo : core::fmt::Debug` error: aborting due to previous error ``` Fixes #20941.
2 parents a8dbd71 + a006a82 commit cffaf0e

File tree

4 files changed

+120
-32
lines changed

4 files changed

+120
-32
lines changed

src/librustc_typeck/check/method/mod.rs

+30-9
Original file line numberDiff line numberDiff line change
@@ -16,7 +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::{self, AsPredicate, ToPolyTraitRef};
19+
use middle::ty::{self, AsPredicate, ToPolyTraitRef, TraitRef};
2020
use middle::infer;
2121

2222
use syntax::ast::DefId;
@@ -32,11 +32,9 @@ mod confirm;
3232
mod probe;
3333
mod suggest;
3434

35-
pub enum MethodError {
36-
// Did not find an applicable method, but we did find various
37-
// static methods that may apply, as well as a list of
38-
// not-in-scope traits which may work.
39-
NoMatch(Vec<CandidateSource>, Vec<ast::DefId>, probe::Mode),
35+
pub enum MethodError<'tcx> {
36+
// Did not find an applicable method, but we did find various near-misses that may work.
37+
NoMatch(NoMatchData<'tcx>),
4038

4139
// Multiple methods might apply.
4240
Ambiguity(Vec<CandidateSource>),
@@ -45,9 +43,32 @@ pub enum MethodError {
4543
ClosureAmbiguity(/* DefId of fn trait */ ast::DefId),
4644
}
4745

46+
// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
47+
// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
48+
pub struct NoMatchData<'tcx> {
49+
pub static_candidates: Vec<CandidateSource>,
50+
pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
51+
pub out_of_scope_traits: Vec<ast::DefId>,
52+
pub mode: probe::Mode
53+
}
54+
55+
impl<'tcx> NoMatchData<'tcx> {
56+
pub fn new(static_candidates: Vec<CandidateSource>,
57+
unsatisfied_predicates: Vec<TraitRef<'tcx>>,
58+
out_of_scope_traits: Vec<ast::DefId>,
59+
mode: probe::Mode) -> Self {
60+
NoMatchData {
61+
static_candidates: static_candidates,
62+
unsatisfied_predicates: unsatisfied_predicates,
63+
out_of_scope_traits: out_of_scope_traits,
64+
mode: mode
65+
}
66+
}
67+
}
68+
4869
// A pared down enum describing just the places from which a method
4970
// candidate can arise. Used for error reporting only.
50-
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
71+
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
5172
pub enum CandidateSource {
5273
ImplSource(ast::DefId),
5374
TraitSource(/* trait id */ ast::DefId),
@@ -93,7 +114,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
93114
supplied_method_types: Vec<ty::Ty<'tcx>>,
94115
call_expr: &'tcx ast::Expr,
95116
self_expr: &'tcx ast::Expr)
96-
-> Result<ty::MethodCallee<'tcx>, MethodError>
117+
-> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
97118
{
98119
debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
99120
method_name,
@@ -305,7 +326,7 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
305326
method_name: ast::Name,
306327
self_ty: ty::Ty<'tcx>,
307328
expr_id: ast::NodeId)
308-
-> Result<(def::Def, LastPrivate), MethodError>
329+
-> Result<(def::Def, LastPrivate), MethodError<'tcx>>
309330
{
310331
let mode = probe::Mode::Path;
311332
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));

src/librustc_typeck/check/method/probe.rs

+50-19
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
// except according to those terms.
1010

1111
use super::MethodError;
12+
use super::NoMatchData;
1213
use super::ItemIndex;
13-
use super::{CandidateSource,ImplSource,TraitSource};
14+
use super::{CandidateSource, ImplSource, TraitSource};
1415
use super::suggest;
1516

1617
use check;
@@ -19,7 +20,7 @@ use middle::fast_reject;
1920
use middle::subst;
2021
use middle::subst::Subst;
2122
use middle::traits;
22-
use middle::ty::{self, RegionEscape, Ty, ToPolyTraitRef};
23+
use middle::ty::{self, RegionEscape, Ty, ToPolyTraitRef, TraitRef};
2324
use middle::ty_fold::TypeFoldable;
2425
use middle::infer;
2526
use middle::infer::InferCtxt;
@@ -42,7 +43,14 @@ struct ProbeContext<'a, 'tcx:'a> {
4243
inherent_candidates: Vec<Candidate<'tcx>>,
4344
extension_candidates: Vec<Candidate<'tcx>>,
4445
impl_dups: HashSet<ast::DefId>,
46+
47+
/// Collects near misses when the candidate functions are missing a `self` keyword and is only
48+
/// used for error reporting
4549
static_candidates: Vec<CandidateSource>,
50+
51+
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
52+
/// for error reporting
53+
unsatisfied_predicates: Vec<TraitRef<'tcx>>
4654
}
4755

4856
#[derive(Debug)]
@@ -104,7 +112,7 @@ pub enum PickKind<'tcx> {
104112
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
105113
}
106114

107-
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
115+
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
108116

109117
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
110118
pub enum Mode {
@@ -141,7 +149,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
141149
let steps = if mode == Mode::MethodCall {
142150
match create_steps(fcx, span, self_ty) {
143151
Some(steps) => steps,
144-
None => return Err(MethodError::NoMatch(Vec::new(), Vec::new(), mode)),
152+
None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(),
153+
Vec::new(), mode))),
145154
}
146155
} else {
147156
vec![CandidateStep {
@@ -242,6 +251,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
242251
steps: Rc::new(steps),
243252
opt_simplified_steps: opt_simplified_steps,
244253
static_candidates: Vec::new(),
254+
unsatisfied_predicates: Vec::new(),
245255
}
246256
}
247257

@@ -563,7 +573,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
563573

564574
fn assemble_extension_candidates_for_traits_in_scope(&mut self,
565575
expr_id: ast::NodeId)
566-
-> Result<(),MethodError>
576+
-> Result<(), MethodError<'tcx>>
567577
{
568578
let mut duplicates = HashSet::new();
569579
let opt_applicable_traits = self.fcx.ccx.trait_map.get(&expr_id);
@@ -577,7 +587,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
577587
Ok(())
578588
}
579589

580-
fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(),MethodError> {
590+
fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
581591
let mut duplicates = HashSet::new();
582592
for trait_info in suggest::all_traits(self.fcx.ccx) {
583593
if duplicates.insert(trait_info.def_id) {
@@ -589,7 +599,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
589599

590600
fn assemble_extension_candidates_for_trait(&mut self,
591601
trait_def_id: ast::DefId)
592-
-> Result<(),MethodError>
602+
-> Result<(), MethodError<'tcx>>
593603
{
594604
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
595605
trait_def_id);
@@ -709,7 +719,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
709719
trait_def_id: ast::DefId,
710720
item: ty::ImplOrTraitItem<'tcx>,
711721
item_index: usize)
712-
-> Result<(),MethodError>
722+
-> Result<(), MethodError<'tcx>>
713723
{
714724
// Check if this is one of the Fn,FnMut,FnOnce traits.
715725
let tcx = self.tcx();
@@ -868,6 +878,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
868878
}
869879

870880
let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
881+
let unsatisfied_predicates = mem::replace(&mut self.unsatisfied_predicates, vec![]);
871882

872883
// things failed, so lets look at all traits, for diagnostic purposes now:
873884
self.reset();
@@ -892,7 +903,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
892903
}
893904
}
894905
}).collect(),
895-
Some(Err(MethodError::NoMatch(_, others, _))) => {
906+
Some(Err(MethodError::NoMatch(NoMatchData { out_of_scope_traits: others, .. }))) => {
896907
assert!(others.is_empty());
897908
vec![]
898909
}
@@ -903,7 +914,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
903914
None => vec![],
904915
};
905916

906-
Err(MethodError::NoMatch(static_candidates, out_of_scope_traits, self.mode))
917+
Err(MethodError::NoMatch(NoMatchData::new(static_candidates, unsatisfied_predicates,
918+
out_of_scope_traits, self.mode)))
907919
}
908920

909921
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
@@ -991,25 +1003,35 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
9911003
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
9921004
debug!("pick_method(self_ty={})", self.infcx().ty_to_string(self_ty));
9931005

1006+
let mut possibly_unsatisfied_predicates = Vec::new();
1007+
9941008
debug!("searching inherent candidates");
995-
match self.consider_candidates(self_ty, &self.inherent_candidates) {
1009+
match self.consider_candidates(self_ty, &self.inherent_candidates,
1010+
&mut possibly_unsatisfied_predicates) {
9961011
None => {}
9971012
Some(pick) => {
9981013
return Some(pick);
9991014
}
10001015
}
10011016

10021017
debug!("searching extension candidates");
1003-
self.consider_candidates(self_ty, &self.extension_candidates)
1018+
let res = self.consider_candidates(self_ty, &self.extension_candidates,
1019+
&mut possibly_unsatisfied_predicates);
1020+
if let None = res {
1021+
self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
1022+
}
1023+
res
10041024
}
10051025

10061026
fn consider_candidates(&self,
10071027
self_ty: Ty<'tcx>,
1008-
probes: &[Candidate<'tcx>])
1028+
probes: &[Candidate<'tcx>],
1029+
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
10091030
-> Option<PickResult<'tcx>> {
10101031
let mut applicable_candidates: Vec<_> =
10111032
probes.iter()
1012-
.filter(|&probe| self.consider_probe(self_ty, probe))
1033+
.filter(|&probe| self.consider_probe(self_ty,
1034+
probe,possibly_unsatisfied_predicates))
10131035
.collect();
10141036

10151037
debug!("applicable_candidates: {:?}", applicable_candidates);
@@ -1032,7 +1054,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
10321054
})
10331055
}
10341056

1035-
fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool {
1057+
fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>,
1058+
possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>) -> bool {
10361059
debug!("consider_probe: self_ty={:?} probe={:?}",
10371060
self_ty,
10381061
probe);
@@ -1071,10 +1094,18 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
10711094
debug!("impl_obligations={:?}", obligations);
10721095

10731096
// Evaluate those obligations to see if they might possibly hold.
1074-
obligations.iter()
1075-
.chain(norm_obligations.iter()).chain(ref_obligations.iter())
1076-
.all(|o| selcx.evaluate_obligation(o))
1077-
1097+
let mut all_true = true;
1098+
for o in obligations.iter()
1099+
.chain(norm_obligations.iter())
1100+
.chain(ref_obligations.iter()) {
1101+
if !selcx.evaluate_obligation(o) {
1102+
all_true = false;
1103+
if let &ty::Predicate::Trait(ref pred) = &o.predicate {
1104+
possibly_unsatisfied_predicates.push(pred.0.trait_ref);
1105+
}
1106+
}
1107+
}
1108+
all_true
10781109
}
10791110

10801111
ProjectionCandidate(..) |

src/librustc_typeck/check/method/suggest.rs

+22-4
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,26 @@ use syntax::print::pprust;
2929
use std::cell;
3030
use std::cmp::Ordering;
3131

32-
use super::{MethodError, CandidateSource, impl_item, trait_item};
32+
use super::{MethodError, NoMatchData, CandidateSource, impl_item, trait_item};
3333
use super::probe::Mode;
3434

3535
pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3636
span: Span,
3737
rcvr_ty: Ty<'tcx>,
3838
item_name: ast::Name,
3939
rcvr_expr: Option<&ast::Expr>,
40-
error: MethodError)
40+
error: MethodError<'tcx>)
4141
{
4242
// avoid suggestions when we don't know what's going on.
4343
if ty::type_is_error(rcvr_ty) {
4444
return
4545
}
4646

4747
match error {
48-
MethodError::NoMatch(static_sources, out_of_scope_traits, mode) => {
48+
MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
49+
unsatisfied_predicates,
50+
out_of_scope_traits,
51+
mode }) => {
4952
let cx = fcx.tcx();
5053

5154
fcx.type_error_message(
@@ -118,13 +121,28 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
118121
}
119122

120123
if !static_sources.is_empty() {
121-
fcx.tcx().sess.fileline_note(
124+
cx.sess.fileline_note(
122125
span,
123126
"found defined static methods, maybe a `self` is missing?");
124127

125128
report_candidates(fcx, span, item_name, static_sources);
126129
}
127130

131+
if !unsatisfied_predicates.is_empty() {
132+
let bound_list = unsatisfied_predicates.iter()
133+
.map(|p| format!("`{} : {}`",
134+
p.self_ty(),
135+
p))
136+
.collect::<Vec<_>>()
137+
.connect(", ");
138+
cx.sess.fileline_note(
139+
span,
140+
&format!("the method `{}` exists but the \
141+
following trait bounds were not satisfied: {}",
142+
item_name,
143+
bound_list));
144+
}
145+
128146
suggest_traits_to_import(fcx, span, rcvr_ty, item_name,
129147
rcvr_expr, out_of_scope_traits)
130148
}
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+
struct Foo;
12+
13+
fn main() {
14+
let a: Result<(), Foo> = Ok(());
15+
a.unwrap();
16+
//~^ ERROR no method named `unwrap` found for type `core::result::Result<(), Foo>`
17+
//~| NOTE the following trait bounds were not satisfied: `Foo : core::fmt::Debug`
18+
}

0 commit comments

Comments
 (0)