Skip to content

Commit cf07ebd

Browse files
committed
move the on_unimplemented logic to its own file
1 parent 243aa12 commit cf07ebd

File tree

3 files changed

+160
-142
lines changed

3 files changed

+160
-142
lines changed

src/librustc/traits/error_reporting.rs

Lines changed: 2 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use super::{
1515
Obligation,
1616
ObligationCause,
1717
ObligationCauseCode,
18+
OnUnimplementedInfo,
1819
OutputTypeParameterMismatch,
1920
TraitNotObjectSafe,
2021
PredicateObligation,
@@ -25,7 +26,6 @@ use super::{
2526
};
2627

2728
use errors::DiagnosticBuilder;
28-
use fmt_macros::{Parser, Piece, Position};
2929
use hir;
3030
use hir::def_id::DefId;
3131
use infer::{self, InferCtxt};
@@ -39,148 +39,9 @@ use ty::fast_reject;
3939
use ty::fold::TypeFolder;
4040
use ty::subst::Subst;
4141
use ty::SubtypePredicate;
42-
use util::common::ErrorReported;
4342
use util::nodemap::{FxHashMap, FxHashSet};
4443

4544
use syntax_pos::{DUMMY_SP, Span};
46-
use syntax_pos::symbol::InternedString;
47-
48-
pub struct OnUnimplementedFormatString(InternedString);
49-
pub struct OnUnimplementedInfo {
50-
note: OnUnimplementedFormatString
51-
}
52-
53-
impl<'a, 'gcx, 'tcx> OnUnimplementedInfo {
54-
pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
55-
trait_def_id: DefId,
56-
impl_def_id: DefId,
57-
span: Span)
58-
-> Result<Option<Self>, ErrorReported>
59-
{
60-
let attrs = tcx.get_attrs(impl_def_id);
61-
62-
let attr = if let Some(item) =
63-
attrs.into_iter().find(|a| a.check_name("rustc_on_unimplemented"))
64-
{
65-
item
66-
} else {
67-
return Ok(None);
68-
};
69-
70-
let span = attr.span.substitute_dummy(span);
71-
if let Some(label) = attr.value_str() {
72-
Ok(Some(OnUnimplementedInfo {
73-
note: OnUnimplementedFormatString::try_parse(
74-
tcx, trait_def_id, label.as_str(), span)?
75-
}))
76-
} else {
77-
struct_span_err!(
78-
tcx.sess, span, E0232,
79-
"this attribute must have a value")
80-
.span_label(attr.span, "attribute requires a value")
81-
.note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
82-
.emit();
83-
Err(ErrorReported)
84-
}
85-
}
86-
}
87-
88-
impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
89-
pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
90-
trait_def_id: DefId,
91-
from: InternedString,
92-
err_sp: Span)
93-
-> Result<Self, ErrorReported>
94-
{
95-
let result = OnUnimplementedFormatString(from);
96-
result.verify(tcx, trait_def_id, err_sp)?;
97-
Ok(result)
98-
}
99-
100-
fn verify(&self,
101-
tcx: TyCtxt<'a, 'gcx, 'tcx>,
102-
trait_def_id: DefId,
103-
span: Span)
104-
-> Result<(), ErrorReported>
105-
{
106-
let name = tcx.item_name(trait_def_id).as_str();
107-
let generics = tcx.generics_of(trait_def_id);
108-
let parser = Parser::new(&self.0);
109-
let types = &generics.types;
110-
let mut result = Ok(());
111-
for token in parser {
112-
match token {
113-
Piece::String(_) => (), // Normal string, no need to check it
114-
Piece::NextArgument(a) => match a.position {
115-
// `{Self}` is allowed
116-
Position::ArgumentNamed(s) if s == "Self" => (),
117-
// `{ThisTraitsName}` is allowed
118-
Position::ArgumentNamed(s) if s == name => (),
119-
// So is `{A}` if A is a type parameter
120-
Position::ArgumentNamed(s) => match types.iter().find(|t| {
121-
t.name == s
122-
}) {
123-
Some(_) => (),
124-
None => {
125-
span_err!(tcx.sess, span, E0230,
126-
"there is no type parameter \
127-
{} on trait {}",
128-
s, name);
129-
result = Err(ErrorReported);
130-
}
131-
},
132-
// `{:1}` and `{}` are not to be used
133-
Position::ArgumentIs(_) => {
134-
span_err!(tcx.sess, span, E0231,
135-
"only named substitution \
136-
parameters are allowed");
137-
result = Err(ErrorReported);
138-
}
139-
}
140-
}
141-
}
142-
143-
result
144-
}
145-
146-
fn format(&self,
147-
tcx: TyCtxt<'a, 'gcx, 'tcx>,
148-
trait_ref: ty::TraitRef<'tcx>)
149-
-> String
150-
{
151-
let name = tcx.item_name(trait_ref.def_id).as_str();
152-
let trait_str = tcx.item_path_str(trait_ref.def_id);
153-
let generics = tcx.generics_of(trait_ref.def_id);
154-
let generic_map = generics.types.iter().map(|param| {
155-
(param.name.as_str().to_string(),
156-
trait_ref.substs.type_for_def(param).to_string())
157-
}).collect::<FxHashMap<String, String>>();
158-
159-
let parser = Parser::new(&self.0);
160-
parser.map(|p| {
161-
match p {
162-
Piece::String(s) => s,
163-
Piece::NextArgument(a) => match a.position {
164-
Position::ArgumentNamed(s) => match generic_map.get(s) {
165-
Some(val) => val,
166-
None if s == name => {
167-
&trait_str
168-
}
169-
None => {
170-
bug!("broken on_unimplemented {:?} for {:?}: \
171-
no argument matching {:?}",
172-
self.0, trait_ref, s)
173-
}
174-
},
175-
_ => {
176-
bug!("broken on_unimplemented {:?} - bad \
177-
format arg", self.0)
178-
}
179-
}
180-
}
181-
}).collect()
182-
}
183-
}
18445

18546
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
18647
pub fn report_fulfillment_errors(&self,
@@ -465,7 +326,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
465326
match OnUnimplementedInfo::of_item(
466327
self.tcx, trait_ref.def_id, def_id, obligation.cause.span
467328
) {
468-
Ok(Some(info)) => Some(info.note.format(self.tcx, *trait_ref)),
329+
Ok(Some(info)) => Some(info.label.format(self.tcx, *trait_ref)),
469330
_ => None
470331
}
471332
}

src/librustc/traits/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ use syntax_pos::{Span, DUMMY_SP};
3131
pub use self::coherence::orphan_check;
3232
pub use self::coherence::overlapping_impls;
3333
pub use self::coherence::OrphanCheckErr;
34-
pub use self::error_reporting::OnUnimplementedInfo;
3534
pub use self::fulfill::{FulfillmentContext, RegionObligation};
3635
pub use self::project::MismatchedProjectionTypes;
3736
pub use self::project::{normalize, normalize_projection_type, Normalized};
3837
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
3938
pub use self::object_safety::ObjectSafetyViolation;
4039
pub use self::object_safety::MethodViolationCode;
40+
pub use self::on_unimplemented::OnUnimplementedInfo;
4141
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
4242
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
4343
pub use self::specialize::{SpecializesCache, find_associated_item};
@@ -53,6 +53,7 @@ mod error_reporting;
5353
mod fulfill;
5454
mod project;
5555
mod object_safety;
56+
mod on_unimplemented;
5657
mod select;
5758
mod specialize;
5859
mod structural_impls;
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Copyright 2017 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+
use fmt_macros::{Parser, Piece, Position};
12+
13+
use hir::def_id::DefId;
14+
use ty::{self, TyCtxt};
15+
use util::common::ErrorReported;
16+
use util::nodemap::FxHashMap;
17+
18+
use syntax_pos::Span;
19+
use syntax_pos::symbol::InternedString;
20+
21+
pub struct OnUnimplementedFormatString(InternedString);
22+
pub struct OnUnimplementedInfo {
23+
pub label: OnUnimplementedFormatString
24+
}
25+
26+
impl<'a, 'gcx, 'tcx> OnUnimplementedInfo {
27+
pub fn of_item(tcx: TyCtxt<'a, 'gcx, 'tcx>,
28+
trait_def_id: DefId,
29+
impl_def_id: DefId,
30+
span: Span)
31+
-> Result<Option<Self>, ErrorReported>
32+
{
33+
let attrs = tcx.get_attrs(impl_def_id);
34+
35+
let attr = if let Some(item) =
36+
attrs.into_iter().find(|a| a.check_name("rustc_on_unimplemented"))
37+
{
38+
item
39+
} else {
40+
return Ok(None);
41+
};
42+
43+
let span = attr.span.substitute_dummy(span);
44+
if let Some(label) = attr.value_str() {
45+
Ok(Some(OnUnimplementedInfo {
46+
label: OnUnimplementedFormatString::try_parse(
47+
tcx, trait_def_id, label.as_str(), span)?
48+
}))
49+
} else {
50+
struct_span_err!(
51+
tcx.sess, span, E0232,
52+
"this attribute must have a value")
53+
.span_label(attr.span, "attribute requires a value")
54+
.note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
55+
.emit();
56+
Err(ErrorReported)
57+
}
58+
}
59+
}
60+
61+
impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
62+
pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
63+
trait_def_id: DefId,
64+
from: InternedString,
65+
err_sp: Span)
66+
-> Result<Self, ErrorReported>
67+
{
68+
let result = OnUnimplementedFormatString(from);
69+
result.verify(tcx, trait_def_id, err_sp)?;
70+
Ok(result)
71+
}
72+
73+
fn verify(&self,
74+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
75+
trait_def_id: DefId,
76+
span: Span)
77+
-> Result<(), ErrorReported>
78+
{
79+
let name = tcx.item_name(trait_def_id).as_str();
80+
let generics = tcx.generics_of(trait_def_id);
81+
let parser = Parser::new(&self.0);
82+
let types = &generics.types;
83+
let mut result = Ok(());
84+
for token in parser {
85+
match token {
86+
Piece::String(_) => (), // Normal string, no need to check it
87+
Piece::NextArgument(a) => match a.position {
88+
// `{Self}` is allowed
89+
Position::ArgumentNamed(s) if s == "Self" => (),
90+
// `{ThisTraitsName}` is allowed
91+
Position::ArgumentNamed(s) if s == name => (),
92+
// So is `{A}` if A is a type parameter
93+
Position::ArgumentNamed(s) => match types.iter().find(|t| {
94+
t.name == s
95+
}) {
96+
Some(_) => (),
97+
None => {
98+
span_err!(tcx.sess, span, E0230,
99+
"there is no type parameter \
100+
{} on trait {}",
101+
s, name);
102+
result = Err(ErrorReported);
103+
}
104+
},
105+
// `{:1}` and `{}` are not to be used
106+
Position::ArgumentIs(_) => {
107+
span_err!(tcx.sess, span, E0231,
108+
"only named substitution \
109+
parameters are allowed");
110+
result = Err(ErrorReported);
111+
}
112+
}
113+
}
114+
}
115+
116+
result
117+
}
118+
119+
pub fn format(&self,
120+
tcx: TyCtxt<'a, 'gcx, 'tcx>,
121+
trait_ref: ty::TraitRef<'tcx>)
122+
-> String
123+
{
124+
let name = tcx.item_name(trait_ref.def_id).as_str();
125+
let trait_str = tcx.item_path_str(trait_ref.def_id);
126+
let generics = tcx.generics_of(trait_ref.def_id);
127+
let generic_map = generics.types.iter().map(|param| {
128+
(param.name.as_str().to_string(),
129+
trait_ref.substs.type_for_def(param).to_string())
130+
}).collect::<FxHashMap<String, String>>();
131+
132+
let parser = Parser::new(&self.0);
133+
parser.map(|p| {
134+
match p {
135+
Piece::String(s) => s,
136+
Piece::NextArgument(a) => match a.position {
137+
Position::ArgumentNamed(s) => match generic_map.get(s) {
138+
Some(val) => val,
139+
None if s == name => {
140+
&trait_str
141+
}
142+
None => {
143+
bug!("broken on_unimplemented {:?} for {:?}: \
144+
no argument matching {:?}",
145+
self.0, trait_ref, s)
146+
}
147+
},
148+
_ => {
149+
bug!("broken on_unimplemented {:?} - bad \
150+
format arg", self.0)
151+
}
152+
}
153+
}
154+
}).collect()
155+
}
156+
}

0 commit comments

Comments
 (0)