fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
- ty::TyClosure(def_id, substs) => {
+ ty::Closure(def_id, substs) => {
// I am a horrible monster and I pray for death. When
// we encounter a closure here, it is always a closure
// from within the function that we are currently
let tcx = self.infcx.tcx;
value.fold_with(&mut BottomUpFolder {
tcx,
+ reg_op: |reg| reg,
fldop: |ty| {
- if let ty::TyAnon(def_id, substs) = ty.sty {
+ if let ty::Anon(def_id, substs) = ty.sty {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
// ```
//
// Here, the return type of `foo` references a
- // `TyAnon` indeed, but not one whose value is
+ // `Anon` indeed, but not one whose value is
// presently being inferred. You can get into a
// similar situation with closure return types
// today:
// }
// ```
if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) {
- let anon_parent_def_id = match tcx.hir.expect_item(anon_node_id).node {
- hir::ItemKind::Existential(hir::ExistTy {
- impl_trait_fn: Some(parent),
- ..
- }) => parent,
- _ => {
- let anon_parent_node_id = tcx.hir.get_parent(anon_node_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) {
+ 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 self.parent_def_id == anon_parent_def_id {
+ if in_definition_scope {
return self.fold_anon_ty(ty, def_id, substs);
}
debug!(
"instantiate_anon_types_in_map: \
- encountered anon with wrong parent \
- def_id={:?} \
- anon_parent_def_id={:?}",
- def_id, anon_parent_def_id
+ encountered anon outside it's definition scope \
+ def_id={:?}",
+ def_id,
);
}
}
let tcx = infcx.tcx;
debug!(
- "instantiate_anon_types: TyAnon(def_id={:?}, substs={:?})",
+ "instantiate_anon_types: Anon(def_id={:?}, substs={:?})",
def_id, substs
);
- // Use the same type variable if the exact same TyAnon appears more
+ // Use the same type variable if the exact same Anon appears more
// than once in the return type (e.g. if it's passed to a type alias).
if let Some(anon_defn) = self.anon_types.get(&def_id) {
return anon_defn.concrete_ty;
let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
let predicates_of = tcx.predicates_of(def_id);
+ debug!(
+ "instantiate_anon_types: predicates: {:#?}",
+ predicates_of,
+ );
let bounds = predicates_of.instantiate(tcx, substs);
debug!("instantiate_anon_types: bounds={:?}", bounds);
required_region_bounds
);
+ // make sure that we are in fact defining the *entire* type
+ // e.g. `existential type Foo<T: Bound>: Bar;` needs to be
+ // defined by a function like `fn foo<T: Bound>() -> Foo<T>`.
+ debug!(
+ "instantiate_anon_types: param_env: {:#?}",
+ self.param_env,
+ );
+ debug!(
+ "instantiate_anon_types: generics: {:#?}",
+ tcx.generics_of(def_id),
+ );
+
self.anon_types.insert(
def_id,
AnonTypeDecl {
for predicate in bounds.predicates {
// Change the predicate to refer to the type variable,
- // which will be the concrete type, instead of the TyAnon.
+ // which will be the concrete type, instead of the Anon.
// This also instantiates nested `impl Trait`.
let predicate = self.instantiate_anon_types_in_map(&predicate);
ty_var
}
}
+
+/// Whether `anon_node_id` is a sibling or a child of a sibling of `def_id`
+///
+/// ```rust
+/// pub mod foo {
+/// pub mod bar {
+/// pub existential type Baz;
+///
+/// fn f1() -> Baz { .. }
+/// }
+///
+/// fn f2() -> bar::Baz { .. }
+/// }
+/// ```
+///
+/// Here, `def_id` will be the `DefId` of the existential type `Baz`.
+/// `anon_node_id` is the `NodeId` of the reference to Baz -- so either the return type of f1 or f2.
+/// We will return true if the reference is within the same module as the existential type
+/// So true for f1, false for f2.
+pub fn may_define_existential_type(
+ tcx: TyCtxt,
+ def_id: DefId,
+ anon_node_id: ast::NodeId,
+) -> bool {
+ let mut node_id = tcx
+ .hir
+ .as_local_node_id(def_id)
+ .unwrap();
+ // named existential types can be defined by any siblings or
+ // children of siblings
+ let mod_id = tcx.hir.get_parent(anon_node_id);
+ // so we walk up the node tree until we hit the root or the parent
+ // of the anon type
+ while node_id != mod_id && node_id != ast::CRATE_NODE_ID {
+ node_id = tcx.hir.get_parent(node_id);
+ }
+ // syntactically we are allowed to define the concrete type
+ node_id == mod_id
+}