From 3a8e0afdbcc0a5c5f27b86d2a062a44410c15e0e Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Mon, 8 Oct 2018 21:39:44 +0900 Subject: [PATCH] Reattach all grandchildren when constructing specialization graph. This commit fixes the issue #50452. --- .../traits/specialize/specialization_graph.rs | 27 +++++++++++----- .../specialization/issue-50452.rs | 32 +++++++++++++++++++ .../run-pass/specialization/issue-50452.rs | 29 +++++++++++++++++ 3 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/specialization/issue-50452.rs create mode 100644 src/test/run-pass/specialization/issue-50452.rs diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index e237cab5ea135..24e8f8ef75080 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -73,8 +73,8 @@ enum Inserted { /// The impl was inserted as a new child in this group of children. BecameNewSibling(Option), - /// The impl should replace an existing impl X, because the impl specializes X. - ReplaceChild(DefId), + /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc. + ReplaceChildren(Vec), /// The impl is a specialization of an existing child. ShouldRecurseOn(DefId), @@ -124,6 +124,7 @@ impl<'a, 'gcx, 'tcx> Children { -> Result { let mut last_lint = None; + let mut replace_children = Vec::new(); debug!( "insert(impl_def_id={:?}, simplified_self={:?})", @@ -194,7 +195,7 @@ impl<'a, 'gcx, 'tcx> Children { debug!("placing as parent of TraitRef {:?}", tcx.impl_trait_ref(possible_sibling).unwrap()); - return Ok(Inserted::ReplaceChild(possible_sibling)); + replace_children.push(possible_sibling); } else { if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { traits::overlapping_impls( @@ -211,6 +212,10 @@ impl<'a, 'gcx, 'tcx> Children { } } + if !replace_children.is_empty() { + return Ok(Inserted::ReplaceChildren(replace_children)); + } + // no overlap with any potential siblings, so add as a new sibling debug!("placing as new sibling"); self.insert_blindly(tcx, impl_def_id); @@ -282,7 +287,7 @@ impl<'a, 'gcx, 'tcx> Graph { last_lint = opt_lint; break; } - ReplaceChild(grand_child_to_be) => { + ReplaceChildren(grand_children_to_be) => { // We currently have // // P @@ -302,17 +307,23 @@ impl<'a, 'gcx, 'tcx> Graph { let siblings = self.children .get_mut(&parent) .unwrap(); - siblings.remove_existing(tcx, grand_child_to_be); + for &grand_child_to_be in &grand_children_to_be { + siblings.remove_existing(tcx, grand_child_to_be); + } siblings.insert_blindly(tcx, impl_def_id); } // Set G's parent to N and N's parent to P - self.parent.insert(grand_child_to_be, impl_def_id); + for &grand_child_to_be in &grand_children_to_be { + self.parent.insert(grand_child_to_be, impl_def_id); + } self.parent.insert(impl_def_id, parent); // Add G as N's child. - self.children.entry(impl_def_id).or_default() - .insert_blindly(tcx, grand_child_to_be); + for &grand_child_to_be in &grand_children_to_be { + self.children.entry(impl_def_id).or_default() + .insert_blindly(tcx, grand_child_to_be); + } break; } ShouldRecurseOn(new_parent) => { diff --git a/src/test/compile-fail/specialization/issue-50452.rs b/src/test/compile-fail/specialization/issue-50452.rs new file mode 100644 index 0000000000000..4a8d01d0de2f5 --- /dev/null +++ b/src/test/compile-fail/specialization/issue-50452.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-fail + +#![feature(specialization)] + +pub trait Foo { + fn foo(); +} + +impl Foo for i32 {} +impl Foo for i64 { + fn foo() {} + //~^ERROR `foo` specializes an item from a parent `impl` +} +impl Foo for T { + fn foo() {} +} + +fn main() { + i32::foo(); + i64::foo(); + u8::foo(); +} diff --git a/src/test/run-pass/specialization/issue-50452.rs b/src/test/run-pass/specialization/issue-50452.rs new file mode 100644 index 0000000000000..6dec03f77819b --- /dev/null +++ b/src/test/run-pass/specialization/issue-50452.rs @@ -0,0 +1,29 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// run-pass + +#![feature(specialization)] + +pub trait Foo { + fn foo(); +} + +impl Foo for i32 {} +impl Foo for i64 {} +impl Foo for T { + fn foo() {} +} + +fn main() { + i32::foo(); + i64::foo(); + u8::foo(); +}