Skip to content

Commit 7c2aeb9

Browse files
committed
Auto merge of #52650 - oli-obk:associated_existential_types, r=nikomatsakis
Implement associated existential types r? @nikomatsakis no idea if these work with generic traits. I'm going home for the day 🤣
2 parents 3d0e933 + 33712a8 commit 7c2aeb9

File tree

8 files changed

+186
-30
lines changed

8 files changed

+186
-30
lines changed

src/librustc/infer/anon_types/mod.rs

+34-18
Original file line numberDiff line numberDiff line change
@@ -691,25 +691,41 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
691691
// }
692692
// ```
693693
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
694-
let in_definition_scope = match tcx.hir.expect_item(anon_node_id).node {
695-
// impl trait
696-
hir::ItemKind::Existential(hir::ExistTy {
697-
impl_trait_fn: Some(parent),
698-
..
699-
}) => parent == self.parent_def_id,
700-
// named existential types
701-
hir::ItemKind::Existential(hir::ExistTy {
702-
impl_trait_fn: None,
703-
..
704-
}) => may_define_existential_type(
705-
tcx,
706-
self.parent_def_id,
707-
anon_node_id,
708-
),
709-
_ => {
710-
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
711-
self.parent_def_id == tcx.hir.local_def_id(anon_parent_node_id)
694+
let parent_def_id = self.parent_def_id;
695+
let def_scope_default = || {
696+
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
697+
parent_def_id == tcx.hir.local_def_id(anon_parent_node_id)
698+
};
699+
let in_definition_scope = match tcx.hir.find(anon_node_id) {
700+
Some(hir::map::NodeItem(item)) => match item.node {
701+
// impl trait
702+
hir::ItemKind::Existential(hir::ExistTy {
703+
impl_trait_fn: Some(parent),
704+
..
705+
}) => parent == self.parent_def_id,
706+
// named existential types
707+
hir::ItemKind::Existential(hir::ExistTy {
708+
impl_trait_fn: None,
709+
..
710+
}) => may_define_existential_type(
711+
tcx,
712+
self.parent_def_id,
713+
anon_node_id,
714+
),
715+
_ => def_scope_default(),
712716
},
717+
Some(hir::map::NodeImplItem(item)) => match item.node {
718+
hir::ImplItemKind::Existential(_) => may_define_existential_type(
719+
tcx,
720+
self.parent_def_id,
721+
anon_node_id,
722+
),
723+
_ => def_scope_default(),
724+
},
725+
_ => bug!(
726+
"expected (impl) item, found {}",
727+
tcx.hir.node_to_string(anon_node_id),
728+
),
713729
};
714730
if in_definition_scope {
715731
return self.fold_anon_ty(ty, def_id, substs);

src/librustc/traits/project.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1502,19 +1502,26 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
15021502
let param_env = obligation.param_env;
15031503
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_def_id);
15041504

1505-
let ty = if !assoc_ty.item.defaultness.has_value() {
1505+
if !assoc_ty.item.defaultness.has_value() {
15061506
// This means that the impl is missing a definition for the
15071507
// associated type. This error will be reported by the type
15081508
// checker method `check_impl_items_against_trait`, so here we
15091509
// just return TyError.
15101510
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
15111511
assoc_ty.item.ident,
15121512
obligation.predicate);
1513-
tcx.types.err
1513+
return Progress {
1514+
ty: tcx.types.err,
1515+
obligations: nested,
1516+
};
1517+
}
1518+
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
1519+
let ty = if let ty::AssociatedKind::Existential = assoc_ty.item.kind {
1520+
let item_substs = Substs::identity_for_item(tcx, assoc_ty.item.def_id);
1521+
tcx.mk_anon(assoc_ty.item.def_id, item_substs)
15141522
} else {
15151523
tcx.type_of(assoc_ty.item.def_id)
15161524
};
1517-
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
15181525
Progress {
15191526
ty: ty.subst(tcx, substs),
15201527
obligations: nested,

src/librustc/traits/specialize/specialization_graph.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,19 @@ impl<'a, 'gcx, 'tcx> Ancestors {
377377
trait_def_id: DefId,
378378
) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
379379
self.flat_map(move |node| {
380-
node.items(tcx).filter(move |impl_item| {
381-
impl_item.kind == trait_item_kind &&
382-
tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id)
380+
use ty::AssociatedKind::*;
381+
node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) {
382+
| (Const, Const)
383+
| (Method, Method)
384+
| (Type, Type)
385+
| (Type, Existential)
386+
=> tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
387+
388+
| (Const, _)
389+
| (Method, _)
390+
| (Type, _)
391+
| (Existential, _)
392+
=> false,
383393
}).map(move |item| NodeItem { node: node, item: item })
384394
})
385395
}

src/librustc_typeck/check/wfcheck.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,7 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
211211
}
212212
}
213213
ty::AssociatedKind::Existential => {
214-
// FIXME(oli-obk) implement existential types in trait impls
215-
unimplemented!()
214+
// do nothing, existential types check themselves
216215
}
217216
}
218217

src/librustc_typeck/collect.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -1046,12 +1046,12 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10461046
tcx.mk_fn_def(def_id, substs)
10471047
}
10481048
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
1049-
ImplItemKind::Existential(ref _bounds) => {
1049+
ImplItemKind::Existential(_) => {
10501050
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
10511051
report_assoc_ty_on_inherent_impl(tcx, item.span);
10521052
}
1053-
// FIXME(oli-obk) implement existential types in trait impls
1054-
unimplemented!()
1053+
1054+
find_existential_constraints(tcx, def_id)
10551055
}
10561056
ImplItemKind::Type(ref ty) => {
10571057
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
@@ -1186,8 +1186,10 @@ fn find_existential_constraints<'a, 'tcx>(
11861186
}
11871187
impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> {
11881188
fn check(&mut self, def_id: DefId) {
1189+
trace!("checking {:?}", def_id);
11891190
// don't try to check items that cannot possibly constrain the type
11901191
if !self.tcx.has_typeck_tables(def_id) {
1192+
trace!("no typeck tables for {:?}", def_id);
11911193
return;
11921194
}
11931195
let ty = self
@@ -1244,9 +1246,11 @@ fn find_existential_constraints<'a, 'tcx>(
12441246
let mut locator = ConstraintLocator { def_id, tcx, found: None };
12451247
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
12461248
let parent = tcx.hir.get_parent(node_id);
1249+
trace!("parent_id: {:?}", parent);
12471250
if parent == ast::CRATE_NODE_ID {
12481251
intravisit::walk_crate(&mut locator, tcx.hir.krate());
12491252
} else {
1253+
trace!("parent: {:?}", tcx.hir.get(parent));
12501254
match tcx.hir.get(parent) {
12511255
NodeItem(ref it) => intravisit::walk_item(&mut locator, it),
12521256
NodeImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
@@ -1485,7 +1489,23 @@ fn explicit_predicates_of<'a, 'tcx>(
14851489
&item.generics
14861490
}
14871491

1488-
NodeImplItem(item) => &item.generics,
1492+
NodeImplItem(item) => match item.node {
1493+
ImplItemKind::Existential(ref bounds) => {
1494+
let substs = Substs::identity_for_item(tcx, def_id);
1495+
let anon_ty = tcx.mk_anon(def_id, substs);
1496+
1497+
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
1498+
let bounds = compute_bounds(&icx,
1499+
anon_ty,
1500+
bounds,
1501+
SizedByDefault::Yes,
1502+
tcx.def_span(def_id));
1503+
1504+
predicates.extend(bounds.predicates(tcx, anon_ty));
1505+
&item.generics
1506+
},
1507+
_ => &item.generics,
1508+
}
14891509

14901510
NodeItem(item) => {
14911511
match item.node {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
#![feature(existential_type)]
12+
// compile-pass
13+
14+
trait Bar {}
15+
struct Dummy<U>(U);
16+
impl<V> Bar for Dummy<V> {}
17+
18+
trait Foo<T> {
19+
type Assoc: Bar;
20+
fn foo(t: T) -> Self::Assoc;
21+
}
22+
23+
impl<W> Foo<W> for i32 {
24+
existential type Assoc: Bar;
25+
fn foo(w: W) -> Self::Assoc {
26+
Dummy(w)
27+
}
28+
}
29+
30+
struct NonGeneric;
31+
impl Bar for NonGeneric {}
32+
33+
impl<W> Foo<W> for u32 {
34+
existential type Assoc: Bar;
35+
fn foo(_: W) -> Self::Assoc {
36+
NonGeneric
37+
}
38+
}
39+
40+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
#![feature(existential_type)]
12+
// compile-pass
13+
14+
trait Bar {}
15+
struct Dummy;
16+
impl Bar for Dummy {}
17+
18+
trait Foo {
19+
type Assoc: Bar;
20+
fn foo() -> Self::Assoc;
21+
}
22+
23+
impl Foo for i32 {
24+
existential type Assoc: Bar;
25+
fn foo() -> Self::Assoc {
26+
Dummy
27+
}
28+
}
29+
30+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
#![feature(existential_type)]
12+
// compile-pass
13+
14+
trait Bar {}
15+
struct Dummy;
16+
impl Bar for Dummy {}
17+
18+
trait Foo {
19+
type Assoc: Bar;
20+
fn foo() -> Self::Assoc;
21+
fn bar() -> Self::Assoc;
22+
}
23+
24+
impl Foo for i32 {
25+
existential type Assoc: Bar;
26+
fn foo() -> Self::Assoc {
27+
Dummy
28+
}
29+
fn bar() -> Self::Assoc {
30+
Dummy
31+
}
32+
}
33+
34+
fn main() {}

0 commit comments

Comments
 (0)