]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc/infer/anon_types/mod.rs
New upstream version 1.29.0+dfsg1
[rustc.git] / src / librustc / infer / anon_types / mod.rs
index f068a54ce44479f27a49ce8a1e49d9416f1da2e1..205f8c5ad068caee0ab33b171f14b2aa715f0762 100644 (file)
@@ -434,8 +434,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         instantiated_ty: Ty<'gcx>,
     ) -> Ty<'gcx> {
         debug!(
-            "infer_anon_definition_from_instantiation(instantiated_ty={:?})",
-            instantiated_ty
+            "infer_anon_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})",
+            def_id, instantiated_ty
         );
 
         let gcx = self.tcx.global_tcx();
@@ -653,6 +653,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
         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 {
                     // Check that this is `impl Trait` type is
@@ -690,26 +691,51 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                     // }
                     // ```
                     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::ItemExistential(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,
                         );
                     }
                 }
@@ -742,6 +768,10 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
         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);
 
@@ -751,6 +781,18 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
             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 {
@@ -778,3 +820,42 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
         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
+}