Implement associated existential types
This commit is contained in:
parent
3900bf8ae3
commit
9130efdad3
@ -691,25 +691,41 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
|
||||
// }
|
||||
// ```
|
||||
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
|
||||
let in_definition_scope = match tcx.hir.expect_item(anon_node_id).node {
|
||||
// impl trait
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: Some(parent),
|
||||
..
|
||||
}) => parent == self.parent_def_id,
|
||||
// named existential types
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: None,
|
||||
..
|
||||
}) => may_define_existential_type(
|
||||
tcx,
|
||||
self.parent_def_id,
|
||||
anon_node_id,
|
||||
),
|
||||
_ => {
|
||||
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
|
||||
self.parent_def_id == tcx.hir.local_def_id(anon_parent_node_id)
|
||||
let parent_def_id = self.parent_def_id;
|
||||
let def_scope_default = || {
|
||||
let anon_parent_node_id = tcx.hir.get_parent(anon_node_id);
|
||||
parent_def_id == tcx.hir.local_def_id(anon_parent_node_id)
|
||||
};
|
||||
let in_definition_scope = match tcx.hir.find(anon_node_id) { // read recorded by `find`
|
||||
Some(hir::map::NodeItem(item)) => match item.node {
|
||||
// impl trait
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: Some(parent),
|
||||
..
|
||||
}) => parent == self.parent_def_id,
|
||||
// named existential types
|
||||
hir::ItemKind::Existential(hir::ExistTy {
|
||||
impl_trait_fn: None,
|
||||
..
|
||||
}) => may_define_existential_type(
|
||||
tcx,
|
||||
self.parent_def_id,
|
||||
anon_node_id,
|
||||
),
|
||||
_ => def_scope_default(),
|
||||
},
|
||||
Some(hir::map::NodeImplItem(item)) => match item.node {
|
||||
hir::ImplItemKind::Existential(_) => may_define_existential_type(
|
||||
tcx,
|
||||
self.parent_def_id,
|
||||
anon_node_id,
|
||||
),
|
||||
_ => def_scope_default(),
|
||||
},
|
||||
_ => bug!(
|
||||
"expected (impl) item, found {}",
|
||||
tcx.hir.node_to_string(anon_node_id),
|
||||
),
|
||||
};
|
||||
if in_definition_scope {
|
||||
return self.fold_anon_ty(ty, def_id, substs);
|
||||
|
@ -1502,7 +1502,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
|
||||
let param_env = obligation.param_env;
|
||||
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_def_id);
|
||||
|
||||
let ty = if !assoc_ty.item.defaultness.has_value() {
|
||||
if !assoc_ty.item.defaultness.has_value() {
|
||||
// This means that the impl is missing a definition for the
|
||||
// associated type. This error will be reported by the type
|
||||
// checker method `check_impl_items_against_trait`, so here we
|
||||
@ -1510,11 +1510,17 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
|
||||
debug!("confirm_impl_candidate: no associated type {:?} for {:?}",
|
||||
assoc_ty.item.ident,
|
||||
obligation.predicate);
|
||||
tcx.types.err
|
||||
return Progress {
|
||||
ty: tcx.types.err,
|
||||
obligations: nested,
|
||||
};
|
||||
}
|
||||
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
|
||||
let ty = if let ty::AssociatedKind::Existential = assoc_ty.item.kind {
|
||||
tcx.mk_anon(assoc_ty.item.def_id, substs)
|
||||
} else {
|
||||
tcx.type_of(assoc_ty.item.def_id)
|
||||
};
|
||||
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
|
||||
Progress {
|
||||
ty: ty.subst(tcx, substs),
|
||||
obligations: nested,
|
||||
|
@ -377,9 +377,15 @@ impl<'a, 'gcx, 'tcx> Ancestors {
|
||||
trait_def_id: DefId,
|
||||
) -> impl Iterator<Item = NodeItem<ty::AssociatedItem>> + Captures<'gcx> + Captures<'tcx> + 'a {
|
||||
self.flat_map(move |node| {
|
||||
node.items(tcx).filter(move |impl_item| {
|
||||
impl_item.kind == trait_item_kind &&
|
||||
tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id)
|
||||
use ty::AssociatedKind::*;
|
||||
node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) {
|
||||
| (Const, Const)
|
||||
| (Method, Method)
|
||||
| (Type, Type)
|
||||
| (Type, Existential)
|
||||
=> tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
|
||||
|
||||
_ => false,
|
||||
}).map(move |item| NodeItem { node: node, item: item })
|
||||
})
|
||||
}
|
||||
|
@ -211,8 +211,7 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
}
|
||||
ty::AssociatedKind::Existential => {
|
||||
// FIXME(oli-obk) implement existential types in trait impls
|
||||
unimplemented!()
|
||||
// do nothing, existential types check themselves
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1046,12 +1046,12 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tcx.mk_fn_def(def_id, substs)
|
||||
}
|
||||
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
|
||||
ImplItemKind::Existential(ref _bounds) => {
|
||||
ImplItemKind::Existential(_) => {
|
||||
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
|
||||
report_assoc_ty_on_inherent_impl(tcx, item.span);
|
||||
}
|
||||
// FIXME(oli-obk) implement existential types in trait impls
|
||||
unimplemented!()
|
||||
|
||||
find_existential_constraints(tcx, def_id)
|
||||
}
|
||||
ImplItemKind::Type(ref ty) => {
|
||||
if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
|
||||
@ -1186,8 +1186,10 @@ fn find_existential_constraints<'a, 'tcx>(
|
||||
}
|
||||
impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> {
|
||||
fn check(&mut self, def_id: DefId) {
|
||||
trace!("checking {:?}", def_id);
|
||||
// don't try to check items that cannot possibly constrain the type
|
||||
if !self.tcx.has_typeck_tables(def_id) {
|
||||
trace!("no typeck tables for {:?}", def_id);
|
||||
return;
|
||||
}
|
||||
let ty = self
|
||||
@ -1244,9 +1246,11 @@ fn find_existential_constraints<'a, 'tcx>(
|
||||
let mut locator = ConstraintLocator { def_id, tcx, found: None };
|
||||
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||
let parent = tcx.hir.get_parent(node_id);
|
||||
trace!("parent_id: {:?}", parent);
|
||||
if parent == ast::CRATE_NODE_ID {
|
||||
intravisit::walk_crate(&mut locator, tcx.hir.krate());
|
||||
} else {
|
||||
trace!("parent: {:?}", tcx.hir.get(parent));
|
||||
match tcx.hir.get(parent) {
|
||||
NodeItem(ref it) => intravisit::walk_item(&mut locator, it),
|
||||
NodeImplItem(ref it) => intravisit::walk_impl_item(&mut locator, it),
|
||||
@ -1485,7 +1489,23 @@ fn explicit_predicates_of<'a, 'tcx>(
|
||||
&item.generics
|
||||
}
|
||||
|
||||
NodeImplItem(item) => &item.generics,
|
||||
NodeImplItem(item) => match item.node {
|
||||
ImplItemKind::Existential(ref bounds) => {
|
||||
let substs = Substs::identity_for_item(tcx, def_id);
|
||||
let anon_ty = tcx.mk_anon(def_id, substs);
|
||||
|
||||
// Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
|
||||
let bounds = compute_bounds(&icx,
|
||||
anon_ty,
|
||||
bounds,
|
||||
SizedByDefault::Yes,
|
||||
tcx.def_span(def_id));
|
||||
|
||||
predicates.extend(bounds.predicates(tcx, anon_ty));
|
||||
&item.generics
|
||||
},
|
||||
_ => &item.generics,
|
||||
}
|
||||
|
||||
NodeItem(item) => {
|
||||
match item.node {
|
||||
|
@ -0,0 +1,30 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(existential_type)]
|
||||
// compile-pass
|
||||
|
||||
trait Bar {}
|
||||
struct Dummy;
|
||||
impl Bar for Dummy {}
|
||||
|
||||
trait Foo {
|
||||
type Assoc: Bar;
|
||||
fn foo() -> Self::Assoc;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
existential type Assoc: Bar;
|
||||
fn foo() -> Self::Assoc {
|
||||
Dummy
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
34
src/test/ui/impl-trait/associated-existential-type.rs
Normal file
34
src/test/ui/impl-trait/associated-existential-type.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(existential_type)]
|
||||
// compile-pass
|
||||
|
||||
trait Bar {}
|
||||
struct Dummy;
|
||||
impl Bar for Dummy {}
|
||||
|
||||
trait Foo {
|
||||
type Assoc: Bar;
|
||||
fn foo() -> Self::Assoc;
|
||||
fn bar() -> Self::Assoc;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
existential type Assoc: Bar;
|
||||
fn foo() -> Self::Assoc {
|
||||
Dummy
|
||||
}
|
||||
fn bar() -> Self::Assoc {
|
||||
Dummy
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user