Skip to content

Commit 0a61d68

Browse files
committed
introduce placeholder-placeholder errors for trait matching
1 parent 1597f2a commit 0a61d68

File tree

13 files changed

+273
-99
lines changed

13 files changed

+273
-99
lines changed

src/librustc/infer/error_reporting/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
339339
}
340340

341341
RegionResolutionError::SubSupConflict(
342+
_,
342343
var_origin,
343344
sub_origin,
344345
sub_r,
@@ -407,7 +408,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
407408
errors.sort_by_key(|u| match *u {
408409
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
409410
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
410-
RegionResolutionError::SubSupConflict(ref rvo, _, _, _, _) => rvo.span(),
411+
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
411412
});
412413
errors
413414
}

src/librustc/infer/error_reporting/nice_region_error/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use util::common::ErrorReported;
88
mod different_lifetimes;
99
mod find_anon_type;
1010
mod named_anon_conflict;
11+
mod placeholder_error;
1112
mod outlives_closure;
1213
mod static_impl_trait;
1314
mod util;
@@ -58,19 +59,20 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> {
5859
// Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
5960
// the nice region errors are required when running under the MIR borrow checker.
6061
self.try_report_named_anon_conflict()
62+
.or_else(|| self.try_report_placeholder_conflict())
6163
}
6264

6365
pub fn try_report(&self) -> Option<ErrorReported> {
64-
self.try_report_named_anon_conflict()
66+
self.try_report_from_nll()
6567
.or_else(|| self.try_report_anon_anon_conflict())
6668
.or_else(|| self.try_report_outlives_closure())
6769
.or_else(|| self.try_report_static_impl_trait())
6870
}
6971

7072
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
7173
match (&self.error, self.regions) {
72-
(&Some(ConcreteFailure(ref origin, sub, sup)), None) => (origin.span(), sub, sup),
73-
(&Some(SubSupConflict(_, ref origin, sub, _, sup)), None) => (origin.span(), sub, sup),
74+
(Some(ConcreteFailure(origin, sub, sup)), None) => (origin.span(), sub, sup),
75+
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => (origin.span(), sub, sup),
7476
(None, Some((span, sub, sup))) => (span, sub, sup),
7577
(Some(_), Some(_)) => panic!("incorrectly built NiceRegionError"),
7678
_ => panic!("trying to report on an incorrect lifetime failure"),

src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
3636
/// ...because it cannot outlive this closure
3737
/// ```
3838
pub(super) fn try_report_outlives_closure(&self) -> Option<ErrorReported> {
39-
if let Some(SubSupConflict(origin,
39+
if let Some(SubSupConflict(_,
40+
origin,
4041
ref sub_origin,
4142
_,
4243
ref sup_origin,
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
use hir::def_id::DefId;
2+
use infer::error_reporting::nice_region_error::NiceRegionError;
3+
use infer::lexical_region_resolve::RegionResolutionError;
4+
use infer::ValuePairs;
5+
use infer::{SubregionOrigin, TypeTrace};
6+
use traits::{ObligationCause, ObligationCauseCode};
7+
use ty;
8+
use ty::error::ExpectedFound;
9+
use ty::subst::Substs;
10+
use util::common::ErrorReported;
11+
use util::ppaux::RegionHighlightMode;
12+
13+
impl NiceRegionError<'me, 'gcx, 'tcx> {
14+
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
15+
/// an anonymous region, emit an descriptive diagnostic error.
16+
pub(super) fn try_report_placeholder_conflict(&self) -> Option<ErrorReported> {
17+
// Check for the first case: relating two trait-refs, and we
18+
// find a conflict between two placeholders.
19+
match &self.error {
20+
Some(RegionResolutionError::SubSupConflict(
21+
vid,
22+
_,
23+
SubregionOrigin::Subtype(TypeTrace {
24+
cause,
25+
values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
26+
}),
27+
ty::RePlaceholder(sub_placeholder),
28+
_,
29+
ty::RePlaceholder(sup_placeholder),
30+
)) => if expected.def_id == found.def_id {
31+
return Some(self.try_report_two_placeholders_trait(
32+
Some(*vid),
33+
cause,
34+
Some(*sub_placeholder),
35+
Some(*sup_placeholder),
36+
expected.def_id,
37+
expected.substs,
38+
found.substs,
39+
));
40+
} else {
41+
// I actually can't see why this would be the case ever.
42+
},
43+
44+
_ => {}
45+
}
46+
47+
None
48+
}
49+
50+
// error[E0308]: implementation of `Foo` does not apply to enough lifetimes
51+
// --> /home/nmatsakis/tmp/foo.rs:12:5
52+
// |
53+
// 12 | all::<&'static u32>();
54+
// | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch
55+
// |
56+
// = note: Due to a where-clause on the function `all`,
57+
// = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
58+
// = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
59+
fn try_report_two_placeholders_trait(
60+
&self,
61+
vid: Option<ty::RegionVid>,
62+
cause: &ObligationCause<'tcx>,
63+
sub_placeholder: Option<ty::PlaceholderRegion>,
64+
sup_placeholder: Option<ty::PlaceholderRegion>,
65+
trait_def_id: DefId,
66+
expected_substs: &'tcx Substs<'tcx>,
67+
actual_substs: &'tcx Substs<'tcx>,
68+
) -> ErrorReported {
69+
let mut err = self.tcx.sess.struct_span_err(
70+
cause.span(&self.tcx),
71+
&format!(
72+
"implementation of `{}` is not general enough",
73+
self.tcx.item_path_str(trait_def_id),
74+
),
75+
);
76+
77+
match cause.code {
78+
ObligationCauseCode::ItemObligation(def_id) => {
79+
err.note(&format!(
80+
"Due to a where-clause on `{}`,",
81+
self.tcx.item_path_str(def_id),
82+
));
83+
}
84+
_ => (),
85+
}
86+
87+
let expected_trait_ref = ty::TraitRef {
88+
def_id: trait_def_id,
89+
substs: expected_substs,
90+
};
91+
let actual_trait_ref = ty::TraitRef {
92+
def_id: trait_def_id,
93+
substs: actual_substs,
94+
};
95+
96+
// Search the expected and actual trait references to see (a)
97+
// whether the sub/sup placeholders appear in them (sometimes
98+
// you have a trait ref like `T: Foo<fn(&u8)>`, where the
99+
// placeholder was created as part of an inner type) and (b)
100+
// whether the inference variable appears. In each case,
101+
// assign a counter value in each case if so.
102+
let mut counter = 0;
103+
let mut has_sub = None;
104+
let mut has_sup = None;
105+
let mut has_vid = None;
106+
107+
self.tcx
108+
.for_each_free_region(&expected_trait_ref, |r| match r {
109+
ty::RePlaceholder(p) => {
110+
if Some(*p) == sub_placeholder {
111+
if has_sub.is_none() {
112+
has_sub = Some(counter);
113+
counter += 1;
114+
}
115+
} else if Some(*p) == sup_placeholder {
116+
if has_sup.is_none() {
117+
has_sup = Some(counter);
118+
counter += 1;
119+
}
120+
}
121+
}
122+
_ => {}
123+
});
124+
125+
self.tcx
126+
.for_each_free_region(&actual_trait_ref, |r| match r {
127+
ty::ReVar(v) if Some(*v) == vid => {
128+
if has_vid.is_none() {
129+
has_vid = Some(counter);
130+
counter += 1;
131+
}
132+
}
133+
_ => {}
134+
});
135+
136+
maybe_highlight(
137+
sub_placeholder,
138+
has_sub,
139+
RegionHighlightMode::highlighting_placeholder,
140+
|| {
141+
maybe_highlight(
142+
sup_placeholder,
143+
has_sup,
144+
RegionHighlightMode::highlighting_placeholder,
145+
|| match (has_sub, has_sup) {
146+
(Some(n1), Some(n2)) => {
147+
err.note(&format!(
148+
"`{}` must implement `{}` \
149+
for any two lifetimes `'{}` and `'{}`",
150+
expected_trait_ref.self_ty(),
151+
expected_trait_ref,
152+
std::cmp::min(n1, n2),
153+
std::cmp::max(n1, n2),
154+
));
155+
}
156+
(Some(n), _) | (_, Some(n)) => {
157+
err.note(&format!(
158+
"`{}` must implement `{}` \
159+
for any lifetime `'{}`",
160+
expected_trait_ref.self_ty(),
161+
expected_trait_ref,
162+
n,
163+
));
164+
}
165+
(None, None) => {
166+
err.note(&format!(
167+
"`{}` must implement `{}`",
168+
expected_trait_ref.self_ty(),
169+
expected_trait_ref,
170+
));
171+
}
172+
},
173+
)
174+
},
175+
);
176+
177+
maybe_highlight(
178+
vid,
179+
has_vid,
180+
RegionHighlightMode::highlighting_region_vid,
181+
|| match has_vid {
182+
Some(n) => {
183+
err.note(&format!(
184+
"but `{}` only implements `{}` for some lifetime `'{}`",
185+
actual_trait_ref.self_ty(),
186+
actual_trait_ref,
187+
n
188+
));
189+
}
190+
None => {
191+
err.note(&format!(
192+
"but `{}` only implements `{}`",
193+
actual_trait_ref.self_ty(),
194+
actual_trait_ref,
195+
));
196+
}
197+
},
198+
);
199+
200+
err.emit();
201+
ErrorReported
202+
}
203+
}
204+
205+
/// If both `thing` and `counter` are `Some`, invoke
206+
/// `highlighting_func` with their contents (and the `op`). Else just
207+
/// invoke `op`.
208+
fn maybe_highlight<T, F, R>(
209+
thing: Option<T>,
210+
counter: Option<usize>,
211+
highlighting_func: impl FnOnce(T, usize, F) -> R,
212+
op: F,
213+
) -> R
214+
where
215+
F: FnOnce() -> R,
216+
{
217+
if let Some(thing) = thing {
218+
if let Some(n) = counter {
219+
return highlighting_func(thing, n, op);
220+
}
221+
}
222+
op()
223+
}

src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
1111
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
1212
if let Some(ref error) = self.error {
1313
if let RegionResolutionError::SubSupConflict(
14+
_,
1415
var_origin,
1516
sub_origin,
1617
sub_r,

src/librustc/infer/lexical_region_resolve/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@ pub enum RegionResolutionError<'tcx> {
7373
/// `a` (but none of the known bounds are sufficient).
7474
GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),
7575

76-
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
76+
/// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`:
7777
///
78-
/// Could not infer a value for `v` because `sub_r <= v` (due to
79-
/// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
78+
/// Could not infer a value for `v` (which has origin `v_origin`)
79+
/// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
8080
/// `sub_r <= sup_r` does not hold.
8181
SubSupConflict(
82+
RegionVid,
8283
RegionVariableOrigin,
8384
SubregionOrigin<'tcx>,
8485
Region<'tcx>,
@@ -596,6 +597,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> {
596597
origin, node_idx, lower_bound.region, upper_bound.region
597598
);
598599
errors.push(RegionResolutionError::SubSupConflict(
600+
node_idx,
599601
origin,
600602
lower_bound.origin.clone(),
601603
lower_bound.region,

src/test/ui/associated-types/associated-types-eq-hr.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,12 @@ pub fn call_bar() {
8989

9090
pub fn call_tuple_one() {
9191
tuple_one::<Tuple>();
92-
//~^ ERROR E0495
93-
//~| ERROR E0495
92+
//~^ ERROR not general enough
9493
}
9594

9695
pub fn call_tuple_two() {
9796
tuple_two::<Tuple>();
98-
//~^ ERROR E0495
99-
//~| ERROR E0495
97+
//~^ ERROR not general enough
10098
}
10199

102100
pub fn call_tuple_three() {
@@ -105,7 +103,7 @@ pub fn call_tuple_three() {
105103

106104
pub fn call_tuple_four() {
107105
tuple_four::<Tuple>();
108-
//~^ ERROR E0495
106+
//~^ ERROR not general enough
109107
}
110108

111109
fn main() { }

0 commit comments

Comments
 (0)