}
/// 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,
def_id: DefId)
-> ParamEnv<'tcx> {
- // The param_env of an existential type is its parent's param_env
+ // The param_env of an impl Trait type is its defining function's param_env
if let Some(Def::Existential(_)) = tcx.describe_def(def_id) {
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
if let hir::map::NodeItem(item) = tcx.hir.get(node_id) {
check_where_clauses(tcx, fcx, span, def_id, Some(sig.output()));
}
+/// Checks "defining uses" of existential types to ensure that they meet the restrictions laid for
+/// "higher-order pattern unification".
+/// This ensures that inference is tractable.
+/// In particular, definitions of existential types can only use other generics as arguments,
+/// and they cannot repeat an argument. Example:
+///
+/// ```rust
+/// existential type Foo<A, B>;
+///
+/// // ok -- `Foo` is applied to two distinct, generic types.
+/// fn a<T, U>() -> Foo<T, U> { .. }
+///
+/// // not ok -- `Foo` is applied to `T` twice.
+/// fn b<T>() -> Foo<T, T> { .. }
+///
+///
+/// // not ok -- `Foo` is applied to a non-generic type.
+/// fn b<T>() -> Foo<T, u32> { .. }
+/// ```
+///
fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'gcx>,
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,