Skip to content

Commit d8406a3

Browse files
Extend rustc_on_unimplemented flag: if a message is available at an impl, this message will be displayed instead
1 parent 4b87655 commit d8406a3

File tree

8 files changed

+163
-29
lines changed

8 files changed

+163
-29
lines changed

src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
// Since libcore defines many fundamental lang items, all tests live in a
4444
// separate crate, libcoretest, to avoid bizarre issues.
4545

46+
#![cfg_attr(stage0, allow(unused_attributes))]
4647
#![crate_name = "core"]
4748
#![stable(feature = "core", since = "1.6.0")]
4849
#![crate_type = "rlib"]

src/librustc/middle/infer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
104104

105105
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
106106
/// region that each late-bound region was replaced with.
107-
pub type SkolemizationMap = FnvHashMap<ty::BoundRegion,ty::Region>;
107+
pub type SkolemizationMap = FnvHashMap<ty::BoundRegion, ty::Region>;
108108

109109
/// Why did we require that the two types be related?
110110
///

src/librustc/middle/infer/type_variable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
127127
let (relations, default) = match old_value {
128128
Bounded { relations, default } => (relations, default),
129129
Known(_) => panic!("Asked to instantiate variable that is \
130-
already instantiated")
130+
already instantiated")
131131
};
132132

133133
for &(dir, vid) in &relations {

src/librustc/middle/subst.rs

-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ impl<'tcx> Substs<'tcx> {
175175
}
176176

177177
impl<'tcx> Encodable for Substs<'tcx> {
178-
179178
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
180179
cstore::tls::with_encoding_context(s, |ecx, rbml_w| {
181180
ecx.encode_substs(rbml_w, self);

src/librustc/middle/traits/error_reporting.rs

+102-22
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ use super::{
2525

2626
use fmt_macros::{Parser, Piece, Position};
2727
use middle::def_id::DefId;
28-
use middle::infer::InferCtxt;
28+
use middle::infer::{self, InferCtxt, TypeOrigin};
2929
use middle::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable};
3030
use middle::ty::fast_reject;
31+
use middle::subst::{self, Subst};
3132
use util::nodemap::{FnvHashMap, FnvHashSet};
3233

3334
use std::cmp;
3435
use std::fmt;
36+
use syntax::ast;
3537
use syntax::attr::{AttributeMethods, AttrMetaMethods};
3638
use syntax::codemap::Span;
3739
use syntax::errors::DiagnosticBuilder;
@@ -105,15 +107,93 @@ pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
105107
}
106108
}
107109

110+
fn impl_self_ty<'a, 'tcx>(fcx: &InferCtxt<'a, 'tcx>,
111+
did: DefId,
112+
obligation: PredicateObligation<'tcx>)
113+
-> subst::Substs<'tcx> {
114+
let tcx = fcx.tcx;
115+
116+
let ity = tcx.lookup_item_type(did);
117+
let (tps, rps, _) =
118+
(ity.generics.types.get_slice(subst::TypeSpace),
119+
ity.generics.regions.get_slice(subst::TypeSpace),
120+
ity.ty);
121+
122+
let rps = fcx.region_vars_for_defs(obligation.cause.span, rps);
123+
let mut substs = subst::Substs::new(
124+
subst::VecPerParamSpace::empty(),
125+
subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
126+
fcx.type_vars_for_defs(obligation.cause.span, subst::ParamSpace::TypeSpace, &mut substs, tps);
127+
substs
128+
}
129+
130+
fn get_current_failing_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
131+
trait_ref: &TraitRef<'tcx>,
132+
obligation: &PredicateObligation<'tcx>)
133+
-> Option<DefId> {
134+
let simp = fast_reject::simplify_type(infcx.tcx,
135+
trait_ref.self_ty(),
136+
true);
137+
let trait_def = infcx.tcx.lookup_trait_def(trait_ref.def_id);
138+
139+
match simp {
140+
Some(_) => {
141+
let mut ret = None;
142+
trait_def.for_each_impl(infcx.tcx, |def_id| {
143+
let imp = infcx.tcx.impl_trait_ref(def_id).unwrap();
144+
let imp = imp.subst(infcx.tcx, &impl_self_ty(infcx, def_id, obligation.clone()));
145+
if ret.is_none() {
146+
for error in infcx.reported_trait_errors.borrow().iter() {
147+
if let ty::Predicate::Trait(ref t) = error.predicate {
148+
if infer::mk_eqty(infcx, true, TypeOrigin::Misc(obligation.cause.span),
149+
t.skip_binder().trait_ref.self_ty(),
150+
imp.self_ty()).is_ok() {
151+
ret = Some(def_id);
152+
break;
153+
}
154+
}
155+
}
156+
}
157+
});
158+
ret
159+
},
160+
None => None,
161+
}
162+
}
163+
164+
fn find_attr<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
165+
def_id: DefId,
166+
attr_name: &str)
167+
-> Option<ast::Attribute> {
168+
for item in infcx.tcx.get_attrs(def_id).iter() {
169+
if item.check_name(attr_name) {
170+
return Some(item.clone());
171+
}
172+
}
173+
None
174+
}
175+
108176
fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
109177
trait_ref: &TraitRef<'tcx>,
110-
span: Span) -> Option<String> {
111-
let def_id = trait_ref.def_id;
178+
obligation: &PredicateObligation<'tcx>)
179+
-> Option<String> {
180+
let def_id = match get_current_failing_impl(infcx, trait_ref, obligation) {
181+
Some(def_id) => {
182+
if let Some(_) = find_attr(infcx, def_id, "rustc_on_unimplemented") {
183+
def_id
184+
} else {
185+
trait_ref.def_id
186+
}
187+
},
188+
None => trait_ref.def_id,
189+
};
190+
let span = obligation.cause.span;
112191
let mut report = None;
192+
113193
for item in infcx.tcx.get_attrs(def_id).iter() {
114194
if item.check_name("rustc_on_unimplemented") {
115195
let err_sp = item.meta().span.substitute_dummy(span);
116-
let def = infcx.tcx.lookup_trait_def(def_id);
196+
let def = infcx.tcx.lookup_trait_def(trait_ref.def_id);
117197
let trait_str = def.trait_ref.to_string();
118198
if let Some(ref istring) = item.value_str() {
119199
let mut generic_map = def.generics.types.iter_enumerated()
@@ -134,24 +214,24 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
134214
Some(val) => Some(val),
135215
None => {
136216
span_err!(infcx.tcx.sess, err_sp, E0272,
137-
"the #[rustc_on_unimplemented] \
138-
attribute on \
139-
trait definition for {} refers to \
140-
non-existent type parameter {}",
141-
trait_str, s);
217+
"the #[rustc_on_unimplemented] \
218+
attribute on \
219+
trait definition for {} refers to \
220+
non-existent type parameter {}",
221+
trait_str, s);
142222
errored = true;
143223
None
144224
}
145225
},
146226
_ => {
147-
span_err!(infcx.tcx.sess, err_sp, E0273,
148-
"the #[rustc_on_unimplemented] \
149-
attribute on \
150-
trait definition for {} must have named \
151-
format arguments, \
152-
eg `#[rustc_on_unimplemented = \
153-
\"foo {{T}}\"]`",
154-
trait_str);
227+
span_err!(infcx.tcx.sess, err_sp, E0273,
228+
"the #[rustc_on_unimplemented] \
229+
attribute on \
230+
trait definition for {} must have named \
231+
format arguments, \
232+
eg `#[rustc_on_unimplemented = \
233+
\"foo {{T}}\"]`",
234+
trait_str);
155235
errored = true;
156236
None
157237
}
@@ -164,10 +244,10 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
164244
}
165245
} else {
166246
span_err!(infcx.tcx.sess, err_sp, E0274,
167-
"the #[rustc_on_unimplemented] attribute on \
168-
trait definition for {} must have a value, \
169-
eg `#[rustc_on_unimplemented = \"foo\"]`",
170-
trait_str);
247+
"the #[rustc_on_unimplemented] attribute on \
248+
trait definition for {} must have a value, \
249+
eg `#[rustc_on_unimplemented = \"foo\"]`",
250+
trait_str);
171251
}
172252
break;
173253
}
@@ -368,7 +448,7 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
368448
// Check if it has a custom "#[rustc_on_unimplemented]"
369449
// error message, report with that message if it does
370450
let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
371-
obligation.cause.span);
451+
obligation);
372452
if let Some(s) = custom_note {
373453
err.fileline_note(obligation.cause.span, &s);
374454
} else {

src/librustc/middle/traits/project.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,10 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext
198198
/// them with a fully resolved type where possible. The return value
199199
/// combines the normalized result and any additional obligations that
200200
/// were incurred as result.
201-
pub fn normalize<'a,'b,'tcx,T>(selcx: &'a mut SelectionContext<'b,'tcx>,
202-
cause: ObligationCause<'tcx>,
203-
value: &T)
204-
-> Normalized<'tcx, T>
201+
pub fn normalize<'a, 'b, 'tcx, T>(selcx: &'a mut SelectionContext<'b,'tcx>,
202+
cause: ObligationCause<'tcx>,
203+
value: &T)
204+
-> Normalized<'tcx, T>
205205
where T : TypeFoldable<'tcx>
206206
{
207207
normalize_with_depth(selcx, cause, 0, value)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2016 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+
// Test if the on_unimplemented message override works
12+
13+
#![feature(on_unimplemented)]
14+
#![feature(rustc_attrs)]
15+
16+
#[rustc_on_unimplemented = "invalid"]
17+
trait Index<Idx: ?Sized> {
18+
type Output: ?Sized;
19+
fn index(&self, index: Idx) -> &Self::Output;
20+
}
21+
22+
#[rustc_on_unimplemented = "a usize is required to index into a slice"]
23+
impl Index<usize> for [i32] {
24+
type Output = i32;
25+
fn index(&self, index: usize) -> &i32 {
26+
&self[index]
27+
}
28+
}
29+
30+
#[rustc_error]
31+
fn main() {
32+
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277
33+
//~| NOTE a usize is required
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2016 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+
// Test new Index error message for slices
12+
13+
#![feature(rustc_attrs)]
14+
15+
#[rustc_error]
16+
fn main() {
17+
let x = &[1, 2, 3] as &[i32];
18+
x[1i32]; //~ ERROR E0277
19+
//~| NOTE a usize is required
20+
}

0 commit comments

Comments
 (0)