Skip to content

Commit dd76050

Browse files
committed
Merge pull request #3885 from pcwalton/master
rustc: Implement typechecking for automatically-derived enums
2 parents ed48e76 + a369a78 commit dd76050

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

src/rustc/middle/ty.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,11 @@ type ctxt =
387387
deriving_struct_methods: HashMap<ast::def_id,
388388
@~[typeck::method_origin]>,
389389

390+
// The outer vector here describes each enum variant, while the inner
391+
// nested vector describes each enum variant argument.
392+
deriving_enum_methods: HashMap<ast::def_id,
393+
@~[@~[typeck::method_origin]]>,
394+
390395
// A mapping from the def ID of a method that was automatically derived
391396
// to information about it.
392397
automatically_derived_methods: HashMap<ast::def_id, DerivedMethodInfo>,
@@ -959,6 +964,7 @@ fn mk_ctxt(s: session::Session,
959964
provided_method_sources: HashMap(),
960965
supertraits: HashMap(),
961966
deriving_struct_methods: HashMap(),
967+
deriving_enum_methods: HashMap(),
962968
automatically_derived_methods: HashMap(),
963969
automatically_derived_methods_for_impl: HashMap()}
964970
}

src/rustc/middle/typeck/deriving.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,48 @@ impl DerivingChecker {
113113
tcx.deriving_struct_methods.insert(local_def(impl_id), field_info);
114114
}
115115

116+
fn check_deriving_for_enum(enum_def_id: def_id,
117+
enum_substs: &substs,
118+
trait_ref: @trait_ref,
119+
impl_id: node_id,
120+
impl_span: span) {
121+
let tcx = self.crate_context.tcx;
122+
let enum_methods = dvec::DVec();
123+
let variants = ty::substd_enum_variants(
124+
tcx, enum_def_id, enum_substs);
125+
for variants.each |enum_variant_info| {
126+
let variant_methods = dvec::DVec();
127+
for enum_variant_info.args.eachi |i, variant_arg_type| {
128+
match self.check_deriving_for_substructure_type(
129+
*variant_arg_type, trait_ref, impl_span) {
130+
Some(method_target_def_id) => {
131+
variant_methods.push(method_static(
132+
method_target_def_id));
133+
}
134+
None => {
135+
let trait_str = pprust::path_to_str(
136+
trait_ref.path, tcx.sess.parse_sess.interner);
137+
tcx.sess.span_err(impl_span,
138+
fmt!("cannot automatically derive \
139+
an implementation for `%s`: \
140+
argument %u of variant `%s` \
141+
does not implement the trait \
142+
`%s`",
143+
trait_str,
144+
i + 1,
145+
tcx.sess.str_of(
146+
enum_variant_info.name),
147+
trait_str));
148+
}
149+
}
150+
}
151+
enum_methods.push(@dvec::unwrap(move variant_methods));
152+
}
153+
154+
let enum_methods = @dvec::unwrap(move enum_methods);
155+
tcx.deriving_enum_methods.insert(local_def(impl_id), enum_methods);
156+
}
157+
116158
fn check_deriving(crate: @crate) {
117159
let tcx = self.crate_context.tcx;
118160
visit_crate(*crate, (), mk_simple_visitor(@{
@@ -123,8 +165,13 @@ impl DerivingChecker {
123165
let superty = ty::lookup_item_type(
124166
tcx, local_def(item.id)).ty;
125167
match ty::get(superty).sty {
126-
ty_enum(_def_id, _substs) => {
127-
// XXX: Handle enums.
168+
ty_enum(def_id, ref substs) => {
169+
self.check_deriving_for_enum(
170+
def_id,
171+
substs,
172+
trait_ref,
173+
item.id,
174+
item.span);
128175
}
129176
ty_class(def_id, ref substs) => {
130177
self.check_deriving_for_struct(
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
trait MyEq {
2+
pure fn eq(other: &self) -> bool;
3+
}
4+
5+
struct A {
6+
x: int
7+
}
8+
9+
enum B {
10+
C(A),
11+
D(A),
12+
E(A)
13+
}
14+
15+
impl B : MyEq;
16+
//~^ ERROR cannot automatically derive
17+
//~^^ ERROR cannot automatically derive
18+
//~^^^ ERROR cannot automatically derive
19+
20+
fn main() {
21+
let c = C(A { x: 15 });
22+
assert c.eq(&c);
23+
}
24+

0 commit comments

Comments
 (0)