Skip to content

Commit 34c361c

Browse files
committed
when creating an AssociatedItem, read data from impl, not impl item
Before, when we created an AssociatedItem for impl item X, we would read the impl item itself. Now we instead load up the impl I that contains X and read the data from the `ImplItemRef` for X; actually, we do it for all impl items in I pre-emptively. This kills the last source of edges between a method X and a call to a method Y defined in the same impl. Fixes #37121
1 parent 629f5ff commit 34c361c

File tree

7 files changed

+129
-90
lines changed

7 files changed

+129
-90
lines changed

src/librustc/hir/def.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub type DefMap = NodeMap<PathResolution>;
106106
// within.
107107
pub type ExportMap = NodeMap<Vec<Export>>;
108108

109-
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
109+
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
110110
pub struct Export {
111111
pub name: ast::Name, // The name of the target.
112112
pub def: Def, // The definition of the target.

src/librustc/traits/project.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1007,8 +1007,9 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
10071007
// types, which appear not to unify -- so the
10081008
// overlap check succeeds, when it should
10091009
// fail.
1010-
bug!("Tried to project an inherited associated type during \
1011-
coherence checking, which is currently not supported.");
1010+
span_bug!(obligation.cause.span,
1011+
"Tried to project an inherited associated type during \
1012+
coherence checking, which is currently not supported.");
10121013
};
10131014
candidate_set.vec.extend(new_candidate);
10141015
}

src/librustc/ty/mod.rs

+105-60
Original file line numberDiff line numberDiff line change
@@ -2113,69 +2113,111 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21132113
.expect("missing AssociatedItem in metadata");
21142114
}
21152115

2116+
// When the user asks for a given associated item, we
2117+
// always go ahead and convert all the associated items in
2118+
// the container. Note that we are also careful only to
2119+
// ever register a read on the *container* of the assoc
2120+
// item, not the assoc item itself. This prevents changes
2121+
// in the details of an item (for example, the type to
2122+
// which an associated type is bound) from contaminating
2123+
// those tasks that just need to scan the names of items
2124+
// and so forth.
2125+
21162126
let id = self.map.as_local_node_id(def_id).unwrap();
21172127
let parent_id = self.map.get_parent(id);
21182128
let parent_def_id = self.map.local_def_id(parent_id);
2119-
match self.map.get(id) {
2120-
ast_map::NodeTraitItem(trait_item) => {
2121-
let (kind, has_self, has_value) = match trait_item.node {
2122-
hir::MethodTraitItem(ref sig, ref body) => {
2123-
(AssociatedKind::Method, sig.decl.get_self().is_some(),
2124-
body.is_some())
2125-
}
2126-
hir::ConstTraitItem(_, ref value) => {
2127-
(AssociatedKind::Const, false, value.is_some())
2128-
}
2129-
hir::TypeTraitItem(_, ref ty) => {
2130-
(AssociatedKind::Type, false, ty.is_some())
2131-
}
2132-
};
2133-
2134-
AssociatedItem {
2135-
name: trait_item.name,
2136-
kind: kind,
2137-
vis: Visibility::from_hir(&hir::Inherited, id, self),
2138-
defaultness: hir::Defaultness::Default,
2139-
has_value: has_value,
2140-
def_id: def_id,
2141-
container: TraitContainer(parent_def_id),
2142-
method_has_self_argument: has_self
2129+
let parent_item = self.map.expect_item(parent_id);
2130+
match parent_item.node {
2131+
hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => {
2132+
for impl_item_ref in impl_item_refs {
2133+
let assoc_item =
2134+
self.associated_item_from_impl_item_ref(parent_def_id,
2135+
impl_trait_ref.is_some(),
2136+
impl_item_ref);
2137+
self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
21432138
}
21442139
}
2145-
ast_map::NodeImplItem(impl_item) => {
2146-
let (kind, has_self) = match impl_item.node {
2147-
hir::ImplItemKind::Method(ref sig, _) => {
2148-
(AssociatedKind::Method, sig.decl.get_self().is_some())
2149-
}
2150-
hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false),
2151-
hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false)
2152-
};
2153-
2154-
// Trait impl items are always public.
2155-
let public = hir::Public;
2156-
let parent_item = self.map.expect_item(parent_id);
2157-
let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node {
2158-
&public
2159-
} else {
2160-
&impl_item.vis
2161-
};
2162-
2163-
AssociatedItem {
2164-
name: impl_item.name,
2165-
kind: kind,
2166-
vis: Visibility::from_hir(vis, id, self),
2167-
defaultness: impl_item.defaultness,
2168-
has_value: true,
2169-
def_id: def_id,
2170-
container: ImplContainer(parent_def_id),
2171-
method_has_self_argument: has_self
2140+
2141+
hir::ItemTrait(.., ref trait_items) => {
2142+
for trait_item in trait_items {
2143+
let assoc_item =
2144+
self.associated_item_from_trait_item_ref(parent_def_id, trait_item);
2145+
self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
21722146
}
21732147
}
2174-
item => bug!("associated_item: {:?} not an associated item", item)
2148+
2149+
ref r => {
2150+
panic!("unexpected container of associated items: {:?}", r)
2151+
}
21752152
}
2153+
2154+
// memoize wants us to return something, so return
2155+
// the one we generated for this def-id
2156+
*self.associated_items.borrow().get(&def_id).unwrap()
21762157
})
21772158
}
21782159

2160+
fn associated_item_from_trait_item_ref(self,
2161+
parent_def_id: DefId,
2162+
trait_item: &hir::TraitItem)
2163+
-> AssociatedItem {
2164+
let def_id = self.map.local_def_id(trait_item.id);
2165+
2166+
let (kind, has_self, has_value) = match trait_item.node {
2167+
hir::MethodTraitItem(ref sig, ref body) => {
2168+
(AssociatedKind::Method, sig.decl.get_self().is_some(),
2169+
body.is_some())
2170+
}
2171+
hir::ConstTraitItem(_, ref value) => {
2172+
(AssociatedKind::Const, false, value.is_some())
2173+
}
2174+
hir::TypeTraitItem(_, ref ty) => {
2175+
(AssociatedKind::Type, false, ty.is_some())
2176+
}
2177+
};
2178+
2179+
AssociatedItem {
2180+
name: trait_item.name,
2181+
kind: kind,
2182+
vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self),
2183+
defaultness: hir::Defaultness::Default,
2184+
has_value: has_value,
2185+
def_id: def_id,
2186+
container: TraitContainer(parent_def_id),
2187+
method_has_self_argument: has_self
2188+
}
2189+
}
2190+
2191+
fn associated_item_from_impl_item_ref(self,
2192+
parent_def_id: DefId,
2193+
from_trait_impl: bool,
2194+
impl_item_ref: &hir::ImplItemRef)
2195+
-> AssociatedItem {
2196+
let def_id = self.map.local_def_id(impl_item_ref.id.node_id);
2197+
let (kind, has_self) = match impl_item_ref.kind {
2198+
hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
2199+
hir::AssociatedItemKind::Method { has_self } => {
2200+
(ty::AssociatedKind::Method, has_self)
2201+
}
2202+
hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
2203+
};
2204+
2205+
// Trait impl items are always public.
2206+
let public = hir::Public;
2207+
let vis = if from_trait_impl { &public } else { &impl_item_ref.vis };
2208+
2209+
ty::AssociatedItem {
2210+
name: impl_item_ref.name,
2211+
kind: kind,
2212+
vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self),
2213+
defaultness: impl_item_ref.defaultness,
2214+
has_value: true,
2215+
def_id: def_id,
2216+
container: ImplContainer(parent_def_id),
2217+
method_has_self_argument: has_self
2218+
}
2219+
}
2220+
21792221
pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
21802222
self.associated_item_def_ids.memoize(def_id, || {
21812223
if !def_id.is_local() {
@@ -2184,19 +2226,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21842226

21852227
let id = self.map.as_local_node_id(def_id).unwrap();
21862228
let item = self.map.expect_item(id);
2187-
match item.node {
2229+
let vec: Vec<_> = match item.node {
21882230
hir::ItemTrait(.., ref trait_items) => {
2189-
Rc::new(trait_items.iter().map(|trait_item| {
2190-
self.map.local_def_id(trait_item.id)
2191-
}).collect())
2231+
trait_items.iter()
2232+
.map(|trait_item| trait_item.id)
2233+
.map(|id| self.map.local_def_id(id))
2234+
.collect()
21922235
}
21932236
hir::ItemImpl(.., ref impl_item_refs) => {
2194-
Rc::new(impl_item_refs.iter().map(|impl_item_ref| {
2195-
self.map.local_def_id(impl_item_ref.id.node_id)
2196-
}).collect())
2237+
impl_item_refs.iter()
2238+
.map(|impl_item_ref| impl_item_ref.id)
2239+
.map(|id| self.map.local_def_id(id.node_id))
2240+
.collect()
21972241
}
21982242
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait")
2199-
}
2243+
};
2244+
Rc::new(vec)
22002245
})
22012246
}
22022247

src/librustc_typeck/collect.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -731,11 +731,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
731731
ref generics,
732732
ref opt_trait_ref,
733733
ref selfty,
734-
ref _impl_item_ids /* [1] */) => {
735-
// [1]: We really don't want to be inspecting the details
736-
// of impl-items here; it creates bad edges in the
737-
// incr. comp. graph.
738-
734+
_) => {
739735
// Create generics from the generics specified in the impl head.
740736
debug!("convert: ast_generics={:?}", generics);
741737
let def_id = ccx.tcx.map.local_def_id(it.id);

src/librustdoc/visit_ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -507,15 +507,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
507507
// regardless of where they're located.
508508
if !self.inlining {
509509
let items = item_ids.iter()
510-
.map(|&id| self.cx.map.impl_item(id).clone())
510+
.map(|ii| self.cx.map.impl_item(ii.id).clone())
511511
.collect();
512512
let i = Impl {
513513
unsafety: unsafety,
514514
polarity: polarity,
515515
generics: gen.clone(),
516516
trait_: tr.clone(),
517517
for_: ty.clone(),
518-
items: items.clone(),
518+
items: items,
519519
attrs: item.attrs.clone(),
520520
id: item.id,
521521
whence: item.span,

src/test/incremental/change_private_impl_method/struct_point.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020

2121
#![rustc_partition_translated(module="struct_point-point", cfg="rpass2")]
2222

23-
// FIXME(#37121) -- the following two modules *should* be reused but are not
24-
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
25-
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
23+
#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
24+
#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
2625
#![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
2726
#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
2827
#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
@@ -60,8 +59,7 @@ mod point {
6059
mod fn_calls_methods_in_same_impl {
6160
use point::Point;
6261

63-
// FIXME(#37121) -- we should not need to typeck this again
64-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
62+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
6563
pub fn check() {
6664
let x = Point { x: 2.0, y: 2.0 };
6765
x.distance_from_origin();
@@ -72,8 +70,7 @@ mod fn_calls_methods_in_same_impl {
7270
mod fn_calls_methods_in_another_impl {
7371
use point::Point;
7472

75-
// FIXME(#37121) -- we should not need to typeck this again
76-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
73+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
7774
pub fn check() {
7875
let mut x = Point { x: 2.0, y: 2.0 };
7976
x.translate(3.0, 3.0);

src/test/incremental/change_private_impl_method_cc/struct_point.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,23 @@
1919
#![feature(stmt_expr_attributes)]
2020
#![allow(dead_code)]
2121

22-
// FIXME(#37333) -- the following modules *should* be reused but are not
22+
#![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
23+
#![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
24+
25+
// FIXME(#37333) the struct fields get entangled with inherent methods
26+
#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")]
27+
28+
// FIXME(#37720) these two should be reused, but data gets entangled across crates
2329
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
2430
#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
25-
#![rustc_partition_translated(module="struct_point-fn_make_struct", cfg="rpass2")]
26-
#![rustc_partition_translated(module="struct_point-fn_read_field", cfg="rpass2")]
27-
#![rustc_partition_translated(module="struct_point-fn_write_field", cfg="rpass2")]
2831

2932
extern crate point;
3033

3134
/// A fn item that calls (public) methods on `Point` from the same impl which changed
3235
mod fn_calls_methods_in_same_impl {
3336
use point::Point;
3437

35-
// FIXME(#37333) -- we should not need to typeck this again
38+
// FIXME(#37720) data gets entangled across crates
3639
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
3740
pub fn check() {
3841
let x = Point { x: 2.0, y: 2.0 };
@@ -44,9 +47,9 @@ mod fn_calls_methods_in_same_impl {
4447
mod fn_calls_methods_in_another_impl {
4548
use point::Point;
4649

47-
// FIXME(#37333) -- we should not need to typeck this again
50+
// FIXME(#37720) data gets entangled across crates
4851
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
49-
pub fn check() {
52+
pub fn dirty() {
5053
let mut x = Point { x: 2.0, y: 2.0 };
5154
x.translate(3.0, 3.0);
5255
}
@@ -56,8 +59,7 @@ mod fn_calls_methods_in_another_impl {
5659
mod fn_make_struct {
5760
use point::Point;
5861

59-
// FIXME(#37333) -- we should not need to typeck this again
60-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
62+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
6163
pub fn make_origin() -> Point {
6264
Point { x: 2.0, y: 2.0 }
6365
}
@@ -67,8 +69,7 @@ mod fn_make_struct {
6769
mod fn_read_field {
6870
use point::Point;
6971

70-
// FIXME(#37333) -- we should not need to typeck this again
71-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
72+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
7273
pub fn get_x(p: Point) -> f32 {
7374
p.x
7475
}
@@ -78,8 +79,7 @@ mod fn_read_field {
7879
mod fn_write_field {
7980
use point::Point;
8081

81-
// FIXME(#37333) -- we should not need to typeck this again
82-
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
82+
#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
8383
pub fn inc_x(p: &mut Point) {
8484
p.x += 1.0;
8585
}

0 commit comments

Comments
 (0)