Skip to content

Commit 3a8e0af

Browse files
committed
Reattach all grandchildren when constructing specialization graph.
This commit fixes the issue rust-lang#50452.
1 parent 96734ae commit 3a8e0af

File tree

3 files changed

+80
-8
lines changed

3 files changed

+80
-8
lines changed

src/librustc/traits/specialize/specialization_graph.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ enum Inserted {
7373
/// The impl was inserted as a new child in this group of children.
7474
BecameNewSibling(Option<OverlapError>),
7575

76-
/// The impl should replace an existing impl X, because the impl specializes X.
77-
ReplaceChild(DefId),
76+
/// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc.
77+
ReplaceChildren(Vec<DefId>),
7878

7979
/// The impl is a specialization of an existing child.
8080
ShouldRecurseOn(DefId),
@@ -124,6 +124,7 @@ impl<'a, 'gcx, 'tcx> Children {
124124
-> Result<Inserted, OverlapError>
125125
{
126126
let mut last_lint = None;
127+
let mut replace_children = Vec::new();
127128

128129
debug!(
129130
"insert(impl_def_id={:?}, simplified_self={:?})",
@@ -194,7 +195,7 @@ impl<'a, 'gcx, 'tcx> Children {
194195
debug!("placing as parent of TraitRef {:?}",
195196
tcx.impl_trait_ref(possible_sibling).unwrap());
196197

197-
return Ok(Inserted::ReplaceChild(possible_sibling));
198+
replace_children.push(possible_sibling);
198199
} else {
199200
if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
200201
traits::overlapping_impls(
@@ -211,6 +212,10 @@ impl<'a, 'gcx, 'tcx> Children {
211212
}
212213
}
213214

215+
if !replace_children.is_empty() {
216+
return Ok(Inserted::ReplaceChildren(replace_children));
217+
}
218+
214219
// no overlap with any potential siblings, so add as a new sibling
215220
debug!("placing as new sibling");
216221
self.insert_blindly(tcx, impl_def_id);
@@ -282,7 +287,7 @@ impl<'a, 'gcx, 'tcx> Graph {
282287
last_lint = opt_lint;
283288
break;
284289
}
285-
ReplaceChild(grand_child_to_be) => {
290+
ReplaceChildren(grand_children_to_be) => {
286291
// We currently have
287292
//
288293
// P
@@ -302,17 +307,23 @@ impl<'a, 'gcx, 'tcx> Graph {
302307
let siblings = self.children
303308
.get_mut(&parent)
304309
.unwrap();
305-
siblings.remove_existing(tcx, grand_child_to_be);
310+
for &grand_child_to_be in &grand_children_to_be {
311+
siblings.remove_existing(tcx, grand_child_to_be);
312+
}
306313
siblings.insert_blindly(tcx, impl_def_id);
307314
}
308315

309316
// Set G's parent to N and N's parent to P
310-
self.parent.insert(grand_child_to_be, impl_def_id);
317+
for &grand_child_to_be in &grand_children_to_be {
318+
self.parent.insert(grand_child_to_be, impl_def_id);
319+
}
311320
self.parent.insert(impl_def_id, parent);
312321

313322
// Add G as N's child.
314-
self.children.entry(impl_def_id).or_default()
315-
.insert_blindly(tcx, grand_child_to_be);
323+
for &grand_child_to_be in &grand_children_to_be {
324+
self.children.entry(impl_def_id).or_default()
325+
.insert_blindly(tcx, grand_child_to_be);
326+
}
316327
break;
317328
}
318329
ShouldRecurseOn(new_parent) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2018 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+
// compile-fail
12+
13+
#![feature(specialization)]
14+
15+
pub trait Foo {
16+
fn foo();
17+
}
18+
19+
impl Foo for i32 {}
20+
impl Foo for i64 {
21+
fn foo() {}
22+
//~^ERROR `foo` specializes an item from a parent `impl`
23+
}
24+
impl<T> Foo for T {
25+
fn foo() {}
26+
}
27+
28+
fn main() {
29+
i32::foo();
30+
i64::foo();
31+
u8::foo();
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2018 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+
// run-pass
12+
13+
#![feature(specialization)]
14+
15+
pub trait Foo {
16+
fn foo();
17+
}
18+
19+
impl Foo for i32 {}
20+
impl Foo for i64 {}
21+
impl<T> Foo for T {
22+
fn foo() {}
23+
}
24+
25+
fn main() {
26+
i32::foo();
27+
i64::foo();
28+
u8::foo();
29+
}

0 commit comments

Comments
 (0)