]> git.lizzy.rs Git - rust.git/commitdiff
Reorganize `chalk_context::program_clauses`
authorscalexm <alexandre@scalexm.fr>
Fri, 8 Feb 2019 11:44:16 +0000 (12:44 +0100)
committerscalexm <alexandre@scalexm.fr>
Wed, 20 Mar 2019 19:09:26 +0000 (20:09 +0100)
src/librustc_traits/chalk_context/program_clauses.rs [deleted file]
src/librustc_traits/chalk_context/program_clauses/builtin.rs [new file with mode: 0644]
src/librustc_traits/chalk_context/program_clauses/mod.rs [new file with mode: 0644]
src/librustc_traits/chalk_context/program_clauses/primitive.rs [new file with mode: 0644]

diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs
deleted file mode 100644 (file)
index fb7bba3..0000000
+++ /dev/null
@@ -1,610 +0,0 @@
-use rustc::traits::{
-    WellFormed,
-    FromEnv,
-    DomainGoal,
-    GoalKind,
-    Clause,
-    Clauses,
-    ProgramClause,
-    ProgramClauseCategory,
-    Environment,
-};
-use rustc::ty;
-use rustc::ty::subst::{InternalSubsts, Subst};
-use rustc::hir;
-use rustc::hir::def_id::DefId;
-use rustc_target::spec::abi;
-use super::ChalkInferenceContext;
-use crate::lowering::Lower;
-use crate::generic_types;
-use std::iter;
-
-fn assemble_clauses_from_impls<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    trait_def_id: DefId,
-    clauses: &mut Vec<Clause<'tcx>>
-) {
-    tcx.for_each_impl(trait_def_id, |impl_def_id| {
-        clauses.extend(
-            tcx.program_clauses_for(impl_def_id)
-                .into_iter()
-                .cloned()
-        );
-    });
-}
-
-fn assemble_clauses_from_assoc_ty_values<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    trait_def_id: DefId,
-    clauses: &mut Vec<Clause<'tcx>>
-) {
-    tcx.for_each_impl(trait_def_id, |impl_def_id| {
-        for def_id in tcx.associated_item_def_ids(impl_def_id).iter() {
-            clauses.extend(
-                tcx.program_clauses_for(*def_id)
-                    .into_iter()
-                    .cloned()
-            );
-        }
-    });
-}
-
-fn assemble_builtin_sized_impls<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    sized_def_id: DefId,
-    ty: ty::Ty<'tcx>,
-    clauses: &mut Vec<Clause<'tcx>>
-) {
-    let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
-        let clause = ProgramClause {
-            goal: ty::TraitPredicate {
-                trait_ref: ty::TraitRef {
-                    def_id: sized_def_id,
-                    substs: tcx.mk_substs_trait(ty, &[]),
-                },
-            }.lower(),
-            hypotheses: tcx.mk_goals(
-                nested.iter()
-                    .cloned()
-                    .map(|nested_ty| ty::TraitRef {
-                        def_id: sized_def_id,
-                        substs: tcx.mk_substs_trait(nested_ty, &[]),
-                    })
-                    .map(|trait_ref| ty::TraitPredicate { trait_ref })
-                    .map(|pred| GoalKind::DomainGoal(pred.lower()))
-                    .map(|goal_kind| tcx.mk_goal(goal_kind))
-            ),
-            category: ProgramClauseCategory::Other,
-        };
-        // Bind innermost bound vars that may exist in `ty` and `nested`.
-        clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
-    };
-
-    match &ty.sty {
-        // Non parametric primitive types.
-        ty::Bool |
-        ty::Char |
-        ty::Int(..) |
-        ty::Uint(..) |
-        ty::Float(..) |
-        ty::Error |
-        ty::Never => push_builtin_impl(ty, &[]),
-
-        // These ones are always `Sized`.
-        &ty::Array(_, length) => {
-            push_builtin_impl(tcx.mk_ty(ty::Array(generic_types::bound(tcx, 0), length)), &[]);
-        }
-        ty::RawPtr(ptr) => {
-            push_builtin_impl(generic_types::raw_ptr(tcx, ptr.mutbl), &[]);
-        }
-        &ty::Ref(_, _, mutbl) => {
-            push_builtin_impl(generic_types::ref_ty(tcx, mutbl), &[]);
-        }
-        ty::FnPtr(fn_ptr) => {
-            let fn_ptr = fn_ptr.skip_binder();
-            let fn_ptr = generic_types::fn_ptr(
-                tcx,
-                fn_ptr.inputs_and_output.len(),
-                fn_ptr.c_variadic,
-                fn_ptr.unsafety,
-                fn_ptr.abi
-            );
-            push_builtin_impl(fn_ptr, &[]);
-        }
-        &ty::FnDef(def_id, ..) => {
-            push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
-        }
-        &ty::Closure(def_id, ..) => {
-            push_builtin_impl(generic_types::closure(tcx, def_id), &[]);
-        }
-        &ty::Generator(def_id, ..) => {
-            push_builtin_impl(generic_types::generator(tcx, def_id), &[]);
-        }
-
-        // `Sized` if the last type is `Sized` (because else we will get a WF error anyway).
-        &ty::Tuple(type_list) => {
-            let type_list = generic_types::type_list(tcx, type_list.len());
-            push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list);
-        }
-
-        // Struct def
-        ty::Adt(adt_def, _) => {
-            let substs = InternalSubsts::bound_vars_for_item(tcx, adt_def.did);
-            let adt = tcx.mk_ty(ty::Adt(adt_def, substs));
-            let sized_constraint = adt_def.sized_constraint(tcx)
-                .iter()
-                .map(|ty| ty.subst(tcx, substs))
-                .collect::<Vec<_>>();
-            push_builtin_impl(adt, &sized_constraint);
-        }
-
-        // Artificially trigger an ambiguity.
-        ty::Infer(..) => {
-            // Everybody can find at least two types to unify against:
-            // general ty vars, int vars and float vars.
-            push_builtin_impl(tcx.types.i32, &[]);
-            push_builtin_impl(tcx.types.u32, &[]);
-            push_builtin_impl(tcx.types.f32, &[]);
-            push_builtin_impl(tcx.types.f64, &[]);
-        }
-
-        ty::Projection(_projection_ty) => {
-            // FIXME: add builtin impls from the associated type values found in
-            // trait impls of `projection_ty.trait_ref(tcx)`.
-        }
-
-        // The `Sized` bound can only come from the environment.
-        ty::Param(..) |
-        ty::Placeholder(..) |
-        ty::UnnormalizedProjection(..) => (),
-
-        // Definitely not `Sized`.
-        ty::Foreign(..) |
-        ty::Str |
-        ty::Slice(..) |
-        ty::Dynamic(..) |
-        ty::Opaque(..) => (),
-
-        ty::Bound(..) |
-        ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty),
-    }
-}
-
-fn wf_clause_for_raw_ptr<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    mutbl: hir::Mutability
-) -> Clauses<'tcx> {
-    let ptr_ty = generic_types::raw_ptr(tcx, mutbl);
-
-    let wf_clause = ProgramClause {
-        goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)),
-        hypotheses: ty::List::empty(),
-        category: ProgramClauseCategory::WellFormed,
-    };
-    let wf_clause = Clause::Implies(wf_clause);
-
-    // `forall<T> { WellFormed(*const T). }`
-    tcx.mk_clauses(iter::once(wf_clause))
-}
-
-fn wf_clause_for_fn_ptr<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    arity_and_output: usize,
-    c_variadic: bool,
-    unsafety: hir::Unsafety,
-    abi: abi::Abi
-) -> Clauses<'tcx> {
-    let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, c_variadic, unsafety, abi);
-
-    let wf_clause = ProgramClause {
-        goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)),
-        hypotheses: ty::List::empty(),
-        category: ProgramClauseCategory::WellFormed,
-    };
-    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
-
-    // `forall <T1, ..., Tn+1> { WellFormed(for<> fn(T1, ..., Tn) -> Tn+1). }`
-    // where `n + 1` == `arity_and_output`
-    tcx.mk_clauses(iter::once(wf_clause))
-}
-
-fn wf_clause_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> {
-    let ty = generic_types::bound(tcx, 0);
-    let slice_ty = tcx.mk_slice(ty);
-
-    let sized_trait = match tcx.lang_items().sized_trait() {
-        Some(def_id) => def_id,
-        None => return ty::List::empty(),
-    };
-    let sized_implemented = ty::TraitRef {
-        def_id: sized_trait,
-        substs: tcx.mk_substs_trait(ty, ty::List::empty()),
-    };
-    let sized_implemented: DomainGoal<'_> = ty::TraitPredicate {
-        trait_ref: sized_implemented
-    }.lower();
-
-    let wf_clause = ProgramClause {
-        goal: DomainGoal::WellFormed(WellFormed::Ty(slice_ty)),
-        hypotheses: tcx.mk_goals(
-            iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))
-        ),
-        category: ProgramClauseCategory::WellFormed,
-    };
-    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
-
-    // `forall<T> { WellFormed([T]) :- Implemented(T: Sized). }`
-    tcx.mk_clauses(iter::once(wf_clause))
-}
-
-fn wf_clause_for_array<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    length: &'tcx ty::Const<'tcx>
-) -> Clauses<'tcx> {
-    let ty = generic_types::bound(tcx, 0);
-    let array_ty = tcx.mk_ty(ty::Array(ty, length));
-
-    let sized_trait = match tcx.lang_items().sized_trait() {
-        Some(def_id) => def_id,
-        None => return ty::List::empty(),
-    };
-    let sized_implemented = ty::TraitRef {
-        def_id: sized_trait,
-        substs: tcx.mk_substs_trait(ty, ty::List::empty()),
-    };
-    let sized_implemented: DomainGoal<'_> = ty::TraitPredicate {
-        trait_ref: sized_implemented
-    }.lower();
-
-    let wf_clause = ProgramClause {
-        goal: DomainGoal::WellFormed(WellFormed::Ty(array_ty)),
-        hypotheses: tcx.mk_goals(
-            iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))
-        ),
-        category: ProgramClauseCategory::WellFormed,
-    };
-    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
-
-    // `forall<T> { WellFormed([T; length]) :- Implemented(T: Sized). }`
-    tcx.mk_clauses(iter::once(wf_clause))
-}
-
-fn wf_clause_for_tuple<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    arity: usize
-) -> Clauses<'tcx> {
-    let type_list = generic_types::type_list(tcx, arity);
-    let tuple_ty = tcx.mk_ty(ty::Tuple(type_list));
-
-    let sized_trait = match tcx.lang_items().sized_trait() {
-        Some(def_id) => def_id,
-        None => return ty::List::empty(),
-    };
-
-    // If `arity == 0` (i.e. the unit type) or `arity == 1`, this list of
-    // hypotheses is actually empty.
-    let sized_implemented = type_list[0 .. std::cmp::max(arity, 1) - 1].iter()
-        .map(|ty| ty::TraitRef {
-            def_id: sized_trait,
-            substs: tcx.mk_substs_trait(*ty, ty::List::empty()),
-        })
-        .map(|trait_ref| ty::TraitPredicate { trait_ref })
-        .map(|predicate| predicate.lower());
-
-    let wf_clause = ProgramClause {
-        goal: DomainGoal::WellFormed(WellFormed::Ty(tuple_ty)),
-        hypotheses: tcx.mk_goals(
-            sized_implemented.map(|domain_goal| {
-                tcx.mk_goal(GoalKind::DomainGoal(domain_goal))
-            })
-        ),
-        category: ProgramClauseCategory::WellFormed,
-    };
-    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
-
-    // ```
-    // forall<T1, ..., Tn-1, Tn> {
-    //     WellFormed((T1, ..., Tn)) :-
-    //         Implemented(T1: Sized),
-    //         ...
-    //         Implemented(Tn-1: Sized).
-    // }
-    // ```
-    tcx.mk_clauses(iter::once(wf_clause))
-}
-
-fn wf_clause_for_ref<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    mutbl: hir::Mutability
-) -> Clauses<'tcx> {
-    let region = tcx.mk_region(
-        ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
-    );
-    let ty = generic_types::bound(tcx, 1);
-    let ref_ty = tcx.mk_ref(region, ty::TypeAndMut {
-        ty,
-        mutbl,
-    });
-
-    let outlives: DomainGoal<'_> = ty::OutlivesPredicate(ty, region).lower();
-    let wf_clause = ProgramClause {
-        goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)),
-        hypotheses: tcx.mk_goals(
-            iter::once(tcx.mk_goal(outlives.into_goal()))
-        ),
-        category: ProgramClauseCategory::WellFormed,
-    };
-    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
-
-    // `forall<'a, T> { WellFormed(&'a T) :- Outlives(T: 'a). }`
-    tcx.mk_clauses(iter::once(wf_clause))
-}
-
-fn wf_clause_for_fn_def<'tcx>(
-    tcx: ty::TyCtxt<'_, '_, 'tcx>,
-    def_id: DefId
-) -> Clauses<'tcx> {
-    let fn_def = generic_types::fn_def(tcx, def_id);
-
-    let wf_clause = ProgramClause {
-        goal: DomainGoal::WellFormed(WellFormed::Ty(fn_def)),
-        hypotheses: ty::List::empty(),
-        category: ProgramClauseCategory::WellFormed,
-    };
-    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
-
-    // `forall <T1, ..., Tn+1> { WellFormed(fn some_fn(T1, ..., Tn) -> Tn+1). }`
-    // where `def_id` maps to the `some_fn` function definition
-    tcx.mk_clauses(iter::once(wf_clause))
-}
-
-impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
-    pub(super) fn program_clauses_impl(
-        &self,
-        environment: &Environment<'tcx>,
-        goal: &DomainGoal<'tcx>,
-    ) -> Vec<Clause<'tcx>> {
-        use rustc::traits::WhereClause::*;
-        use rustc::infer::canonical::OriginalQueryValues;
-
-        let goal = self.infcx.resolve_type_vars_if_possible(goal);
-
-        debug!("program_clauses(goal = {:?})", goal);
-
-        let mut clauses = match goal {
-            DomainGoal::Holds(Implemented(trait_predicate)) => {
-                // These come from:
-                // * implementations of the trait itself (rule `Implemented-From-Impl`)
-                // * the trait decl (rule `Implemented-From-Env`)
-
-                let mut clauses = vec![];
-
-                assemble_clauses_from_impls(
-                    self.infcx.tcx,
-                    trait_predicate.def_id(),
-                    &mut clauses
-                );
-
-                if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().sized_trait() {
-                    assemble_builtin_sized_impls(
-                        self.infcx.tcx,
-                        trait_predicate.def_id(),
-                        trait_predicate.self_ty(),
-                        &mut clauses
-                    );
-                }
-
-                // FIXME: we need to add special rules for builtin impls:
-                // * `Copy` / `Clone`
-                // * `Sized`
-                // * `Unsize`
-                // * `Generator`
-                // * `FnOnce` / `FnMut` / `Fn`
-                // * trait objects
-                // * auto traits
-
-                // Rule `Implemented-From-Env` will be computed from the environment.
-                clauses
-            }
-
-            DomainGoal::Holds(ProjectionEq(projection_predicate)) => {
-                // These come from:
-                // * the assoc type definition (rule `ProjectionEq-Placeholder`)
-                // * normalization of the assoc ty values (rule `ProjectionEq-Normalize`)
-                // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
-                // * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
-
-                let clauses = self.infcx.tcx.program_clauses_for(
-                    projection_predicate.projection_ty.item_def_id
-                ).into_iter()
-
-                    // only select `ProjectionEq-Placeholder` and `ProjectionEq-Normalize`
-                    .filter(|clause| clause.category() == ProgramClauseCategory::Other)
-
-                    .cloned()
-                    .collect::<Vec<_>>();
-
-                // Rules `Implied-Bound-From-Trait` and `Implied-Bound-From-Type` will be computed
-                // from the environment.
-                clauses
-            }
-
-            // For outlive requirements, just assume they hold. `ResolventOps::resolvent_clause`
-            // will register them as actual region constraints later.
-            DomainGoal::Holds(RegionOutlives(..)) | DomainGoal::Holds(TypeOutlives(..)) => {
-                vec![Clause::Implies(ProgramClause {
-                    goal,
-                    hypotheses: ty::List::empty(),
-                    category: ProgramClauseCategory::Other,
-                })]
-            }
-
-            DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => {
-                // These come from -- the trait decl (rule `WellFormed-TraitRef`).
-                self.infcx.tcx.program_clauses_for(trait_predicate.def_id())
-                    .into_iter()
-
-                    // only select `WellFormed-TraitRef`
-                    .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
-
-                    .cloned()
-                    .collect()
-            }
-
-            DomainGoal::WellFormed(WellFormed::Ty(ty)) => {
-                // These come from:
-                // * the associated type definition if `ty` refers to an unnormalized
-                //   associated type (rule `WellFormed-AssocTy`)
-                // * custom rules for built-in types
-                // * the type definition otherwise (rule `WellFormed-Type`)
-                let clauses = match ty.sty {
-                    ty::Projection(data) => {
-                        self.infcx.tcx.program_clauses_for(data.item_def_id)
-                    }
-
-                    // These types are always WF.
-                    ty::Bool |
-                    ty::Char |
-                    ty::Int(..) |
-                    ty::Uint(..) |
-                    ty::Float(..) |
-                    ty::Str |
-                    ty::Param(..) |
-                    ty::Placeholder(..) |
-                    ty::Error |
-                    ty::Never => {
-                        let wf_clause = ProgramClause {
-                            goal,
-                            hypotheses: ty::List::empty(),
-                            category: ProgramClauseCategory::WellFormed,
-                        };
-                        let wf_clause = Clause::Implies(wf_clause);
-
-                        self.infcx.tcx.mk_clauses(iter::once(wf_clause))
-                    }
-
-                    // Always WF (recall that we do not check for parameters to be WF).
-                    ty::RawPtr(ptr) => wf_clause_for_raw_ptr(self.infcx.tcx, ptr.mutbl),
-
-                    // Always WF (recall that we do not check for parameters to be WF).
-                    ty::FnPtr(fn_ptr) => {
-                        let fn_ptr = fn_ptr.skip_binder();
-                        wf_clause_for_fn_ptr(
-                            self.infcx.tcx,
-                            fn_ptr.inputs_and_output.len(),
-                            fn_ptr.c_variadic,
-                            fn_ptr.unsafety,
-                            fn_ptr.abi
-                        )
-                    }
-
-                    // WF if inner type is `Sized`.
-                    ty::Slice(..) => wf_clause_for_slice(self.infcx.tcx),
-
-                    // WF if inner type is `Sized`.
-                    ty::Array(_, length) => wf_clause_for_array(self.infcx.tcx, length),
-
-                    // WF if all types but the last one are `Sized`.
-                    ty::Tuple(types) => wf_clause_for_tuple(
-                        self.infcx.tcx,
-                        types.len()
-                    ),
-
-                    // WF if `sub_ty` outlives `region`.
-                    ty::Ref(_, _, mutbl) => wf_clause_for_ref(self.infcx.tcx, mutbl),
-
-                    ty::FnDef(def_id, ..) => wf_clause_for_fn_def(self.infcx.tcx, def_id),
-
-                    ty::Dynamic(..) => {
-                        // FIXME: no rules yet for trait objects
-                        ty::List::empty()
-                    }
-
-                    ty::Adt(def, ..) => {
-                        self.infcx.tcx.program_clauses_for(def.did)
-                    }
-
-                    // FIXME: these are probably wrong
-                    ty::Foreign(def_id) |
-                    ty::Closure(def_id, ..) |
-                    ty::Generator(def_id, ..) |
-                    ty::Opaque(def_id, ..) => {
-                        self.infcx.tcx.program_clauses_for(def_id)
-                    }
-
-                    // Artificially trigger an ambiguity.
-                    ty::Infer(..) => {
-                        let tcx = self.infcx.tcx;
-                        let types = [tcx.types.i32, tcx.types.u32, tcx.types.f32, tcx.types.f64];
-                        let clauses = types.iter()
-                            .cloned()
-                            .map(|ty| ProgramClause {
-                                goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
-                                hypotheses: ty::List::empty(),
-                                category: ProgramClauseCategory::WellFormed,
-                            })
-                            .map(|clause| Clause::Implies(clause));
-                        tcx.mk_clauses(clauses)
-                    }
-
-                    ty::GeneratorWitness(..) |
-                    ty::UnnormalizedProjection(..) |
-                    ty::Bound(..) => {
-                        bug!("unexpected type {:?}", ty)
-                    }
-                };
-
-                clauses.into_iter()
-                    .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
-                    .cloned()
-                    .collect()
-            }
-
-            DomainGoal::FromEnv(FromEnv::Trait(..)) => {
-                // These come from:
-                // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
-                // * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
-                // * implied bounds from assoc type defs (rules `Implied-Trait-From-AssocTy`,
-                //   `Implied-Bound-From-AssocTy` and `Implied-WC-From-AssocTy`)
-
-                // All of these rules are computed in the environment.
-                vec![]
-            }
-
-            DomainGoal::FromEnv(FromEnv::Ty(..)) => {
-                // There are no `FromEnv::Ty(..) :- ...` rules (this predicate only
-                // comes from the environment).
-                vec![]
-            }
-
-            DomainGoal::Normalize(projection_predicate) => {
-                // These come from -- assoc ty values (rule `Normalize-From-Impl`).
-                let mut clauses = vec![];
-
-                assemble_clauses_from_assoc_ty_values(
-                    self.infcx.tcx,
-                    projection_predicate.projection_ty.trait_ref(self.infcx.tcx).def_id,
-                    &mut clauses
-                );
-
-                clauses
-            }
-        };
-
-        debug!("program_clauses: clauses = {:?}", clauses);
-        debug!("program_clauses: adding clauses from environment = {:?}", environment);
-
-        let mut _orig_query_values = OriginalQueryValues::default();
-        let canonical_environment = self.infcx.canonicalize_query(
-            environment,
-            &mut _orig_query_values
-        ).value;
-        let env_clauses = self.infcx.tcx.program_clauses_for_env(canonical_environment);
-
-        debug!("program_clauses: env_clauses = {:?}", env_clauses);
-
-        clauses.extend(env_clauses.into_iter().cloned());
-        clauses.extend(environment.clauses.iter().cloned());
-        clauses
-    }
-}
diff --git a/src/librustc_traits/chalk_context/program_clauses/builtin.rs b/src/librustc_traits/chalk_context/program_clauses/builtin.rs
new file mode 100644 (file)
index 0000000..3622cac
--- /dev/null
@@ -0,0 +1,132 @@
+use rustc::traits::{
+    GoalKind,
+    Clause,
+    ProgramClause,
+    ProgramClauseCategory,
+};
+use rustc::ty;
+use rustc::ty::subst::{InternalSubsts, Subst};
+use rustc::hir::def_id::DefId;
+use crate::lowering::Lower;
+use crate::generic_types;
+
+crate fn assemble_builtin_sized_impls<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    sized_def_id: DefId,
+    ty: ty::Ty<'tcx>,
+    clauses: &mut Vec<Clause<'tcx>>
+) {
+    let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
+        let clause = ProgramClause {
+            goal: ty::TraitPredicate {
+                trait_ref: ty::TraitRef {
+                    def_id: sized_def_id,
+                    substs: tcx.mk_substs_trait(ty, &[]),
+                },
+            }.lower(),
+            hypotheses: tcx.mk_goals(
+                nested.iter()
+                    .cloned()
+                    .map(|nested_ty| ty::TraitRef {
+                        def_id: sized_def_id,
+                        substs: tcx.mk_substs_trait(nested_ty, &[]),
+                    })
+                    .map(|trait_ref| ty::TraitPredicate { trait_ref })
+                    .map(|pred| GoalKind::DomainGoal(pred.lower()))
+                    .map(|goal_kind| tcx.mk_goal(goal_kind))
+            ),
+            category: ProgramClauseCategory::Other,
+        };
+        // Bind innermost bound vars that may exist in `ty` and `nested`.
+        clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
+    };
+
+    match &ty.sty {
+        // Non parametric primitive types.
+        ty::Bool |
+        ty::Char |
+        ty::Int(..) |
+        ty::Uint(..) |
+        ty::Float(..) |
+        ty::Error |
+        ty::Never => push_builtin_impl(ty, &[]),
+
+        // These ones are always `Sized`.
+        &ty::Array(_, length) => {
+            push_builtin_impl(tcx.mk_ty(ty::Array(generic_types::bound(tcx, 0), length)), &[]);
+        }
+        ty::RawPtr(ptr) => {
+            push_builtin_impl(generic_types::raw_ptr(tcx, ptr.mutbl), &[]);
+        }
+        &ty::Ref(_, _, mutbl) => {
+            push_builtin_impl(generic_types::ref_ty(tcx, mutbl), &[]);
+        }
+        ty::FnPtr(fn_ptr) => {
+            let fn_ptr = fn_ptr.skip_binder();
+            let fn_ptr = generic_types::fn_ptr(
+                tcx,
+                fn_ptr.inputs_and_output.len(),
+                fn_ptr.c_variadic,
+                fn_ptr.unsafety,
+                fn_ptr.abi
+            );
+            push_builtin_impl(fn_ptr, &[]);
+        }
+        &ty::FnDef(def_id, ..) => {
+            push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
+        }
+        &ty::Closure(def_id, ..) => {
+            push_builtin_impl(generic_types::closure(tcx, def_id), &[]);
+        }
+        &ty::Generator(def_id, ..) => {
+            push_builtin_impl(generic_types::generator(tcx, def_id), &[]);
+        }
+
+        // `Sized` if the last type is `Sized` (because else we will get a WF error anyway).
+        &ty::Tuple(type_list) => {
+            let type_list = generic_types::type_list(tcx, type_list.len());
+            push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list);
+        }
+
+        // Struct def
+        ty::Adt(adt_def, _) => {
+            let substs = InternalSubsts::bound_vars_for_item(tcx, adt_def.did);
+            let adt = tcx.mk_ty(ty::Adt(adt_def, substs));
+            let sized_constraint = adt_def.sized_constraint(tcx)
+                .iter()
+                .map(|ty| ty.subst(tcx, substs))
+                .collect::<Vec<_>>();
+            push_builtin_impl(adt, &sized_constraint);
+        }
+
+        // Artificially trigger an ambiguity.
+        ty::Infer(..) => {
+            // Everybody can find at least two types to unify against:
+            // general ty vars, int vars and float vars.
+            push_builtin_impl(tcx.types.i32, &[]);
+            push_builtin_impl(tcx.types.u32, &[]);
+            push_builtin_impl(tcx.types.f32, &[]);
+            push_builtin_impl(tcx.types.f64, &[]);
+        }
+
+        ty::Projection(_projection_ty) => {
+            // FIXME: add builtin impls from the associated type values found in
+            // trait impls of `projection_ty.trait_ref(tcx)`.
+        }
+
+        // The `Sized` bound can only come from the environment.
+        ty::Param(..) |
+        ty::Placeholder(..) |
+        ty::UnnormalizedProjection(..) => (),
+
+        // Definitely not `Sized`.
+        ty::Foreign(..) |
+        ty::Str |
+        ty::Slice(..) |
+        ty::Dynamic(..) |
+        ty::Opaque(..) => (),
+
+        ty::Bound(..) |
+        ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty),
+    }
+}
diff --git a/src/librustc_traits/chalk_context/program_clauses/mod.rs b/src/librustc_traits/chalk_context/program_clauses/mod.rs
new file mode 100644 (file)
index 0000000..b6fb70b
--- /dev/null
@@ -0,0 +1,298 @@
+mod builtin;
+mod primitive;
+
+use rustc::traits::{
+    WellFormed,
+    FromEnv,
+    DomainGoal,
+    Clause,
+    ProgramClause,
+    ProgramClauseCategory,
+    Environment,
+};
+use rustc::ty;
+use rustc::hir::def_id::DefId;
+use super::ChalkInferenceContext;
+use std::iter;
+
+use self::primitive::*;
+use self::builtin::*;
+
+fn assemble_clauses_from_impls<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    trait_def_id: DefId,
+    clauses: &mut Vec<Clause<'tcx>>
+) {
+    tcx.for_each_impl(trait_def_id, |impl_def_id| {
+        clauses.extend(
+            tcx.program_clauses_for(impl_def_id)
+                .into_iter()
+                .cloned()
+        );
+    });
+}
+
+fn assemble_clauses_from_assoc_ty_values<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    trait_def_id: DefId,
+    clauses: &mut Vec<Clause<'tcx>>
+) {
+    tcx.for_each_impl(trait_def_id, |impl_def_id| {
+        for def_id in tcx.associated_item_def_ids(impl_def_id).iter() {
+            clauses.extend(
+                tcx.program_clauses_for(*def_id)
+                    .into_iter()
+                    .cloned()
+            );
+        }
+    });
+}
+
+impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
+    pub(super) fn program_clauses_impl(
+        &self,
+        environment: &Environment<'tcx>,
+        goal: &DomainGoal<'tcx>,
+    ) -> Vec<Clause<'tcx>> {
+        use rustc::traits::WhereClause::*;
+        use rustc::infer::canonical::OriginalQueryValues;
+
+        let goal = self.infcx.resolve_type_vars_if_possible(goal);
+
+        debug!("program_clauses(goal = {:?})", goal);
+
+        let mut clauses = match goal {
+            DomainGoal::Holds(Implemented(trait_predicate)) => {
+                // These come from:
+                // * implementations of the trait itself (rule `Implemented-From-Impl`)
+                // * the trait decl (rule `Implemented-From-Env`)
+
+                let mut clauses = vec![];
+
+                assemble_clauses_from_impls(
+                    self.infcx.tcx,
+                    trait_predicate.def_id(),
+                    &mut clauses
+                );
+
+                if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().sized_trait() {
+                    assemble_builtin_sized_impls(
+                        self.infcx.tcx,
+                        trait_predicate.def_id(),
+                        trait_predicate.self_ty(),
+                        &mut clauses
+                    );
+                }
+
+                // FIXME: we need to add special rules for other builtin impls:
+                // * `Copy` / `Clone`
+                // * `Generator`
+                // * `FnOnce` / `FnMut` / `Fn`
+                // * trait objects
+                // * auto traits
+
+                // Rule `Implemented-From-Env` will be computed from the environment.
+                clauses
+            }
+
+            DomainGoal::Holds(ProjectionEq(projection_predicate)) => {
+                // These come from:
+                // * the assoc type definition (rule `ProjectionEq-Placeholder`)
+                // * normalization of the assoc ty values (rule `ProjectionEq-Normalize`)
+                // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
+                // * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
+
+                let clauses = self.infcx.tcx.program_clauses_for(
+                    projection_predicate.projection_ty.item_def_id
+                ).into_iter()
+
+                    // only select `ProjectionEq-Placeholder` and `ProjectionEq-Normalize`
+                    .filter(|clause| clause.category() == ProgramClauseCategory::Other)
+
+                    .cloned()
+                    .collect::<Vec<_>>();
+
+                // Rules `Implied-Bound-From-Trait` and `Implied-Bound-From-Type` will be computed
+                // from the environment.
+                clauses
+            }
+
+            // For outlive requirements, just assume they hold. `ResolventOps::resolvent_clause`
+            // will register them as actual region constraints later.
+            DomainGoal::Holds(RegionOutlives(..)) | DomainGoal::Holds(TypeOutlives(..)) => {
+                vec![Clause::Implies(ProgramClause {
+                    goal,
+                    hypotheses: ty::List::empty(),
+                    category: ProgramClauseCategory::Other,
+                })]
+            }
+
+            DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => {
+                // These come from -- the trait decl (rule `WellFormed-TraitRef`).
+                self.infcx.tcx.program_clauses_for(trait_predicate.def_id())
+                    .into_iter()
+
+                    // only select `WellFormed-TraitRef`
+                    .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
+
+                    .cloned()
+                    .collect()
+            }
+
+            DomainGoal::WellFormed(WellFormed::Ty(ty)) => {
+                // These come from:
+                // * the associated type definition if `ty` refers to an unnormalized
+                //   associated type (rule `WellFormed-AssocTy`)
+                // * custom rules for built-in types
+                // * the type definition otherwise (rule `WellFormed-Type`)
+                let clauses = match ty.sty {
+                    ty::Projection(data) => {
+                        self.infcx.tcx.program_clauses_for(data.item_def_id)
+                    }
+
+                    // These types are always WF.
+                    ty::Bool |
+                    ty::Char |
+                    ty::Int(..) |
+                    ty::Uint(..) |
+                    ty::Float(..) |
+                    ty::Str |
+                    ty::Param(..) |
+                    ty::Placeholder(..) |
+                    ty::Error |
+                    ty::Never => {
+                        let wf_clause = ProgramClause {
+                            goal,
+                            hypotheses: ty::List::empty(),
+                            category: ProgramClauseCategory::WellFormed,
+                        };
+                        let wf_clause = Clause::Implies(wf_clause);
+
+                        self.infcx.tcx.mk_clauses(iter::once(wf_clause))
+                    }
+
+                    // Always WF (recall that we do not check for parameters to be WF).
+                    ty::RawPtr(ptr) => wf_clause_for_raw_ptr(self.infcx.tcx, ptr.mutbl),
+
+                    // Always WF (recall that we do not check for parameters to be WF).
+                    ty::FnPtr(fn_ptr) => {
+                        let fn_ptr = fn_ptr.skip_binder();
+                        wf_clause_for_fn_ptr(
+                            self.infcx.tcx,
+                            fn_ptr.inputs_and_output.len(),
+                            fn_ptr.c_variadic,
+                            fn_ptr.unsafety,
+                            fn_ptr.abi
+                        )
+                    }
+
+                    // WF if inner type is `Sized`.
+                    ty::Slice(..) => wf_clause_for_slice(self.infcx.tcx),
+
+                    // WF if inner type is `Sized`.
+                    ty::Array(_, length) => wf_clause_for_array(self.infcx.tcx, length),
+
+                    // WF if all types but the last one are `Sized`.
+                    ty::Tuple(types) => wf_clause_for_tuple(
+                        self.infcx.tcx,
+                        types.len()
+                    ),
+
+                    // WF if `sub_ty` outlives `region`.
+                    ty::Ref(_, _, mutbl) => wf_clause_for_ref(self.infcx.tcx, mutbl),
+
+                    ty::FnDef(def_id, ..) => wf_clause_for_fn_def(self.infcx.tcx, def_id),
+
+                    ty::Dynamic(..) => {
+                        // FIXME: no rules yet for trait objects
+                        ty::List::empty()
+                    }
+
+                    ty::Adt(def, ..) => {
+                        self.infcx.tcx.program_clauses_for(def.did)
+                    }
+
+                    // FIXME: these are probably wrong
+                    ty::Foreign(def_id) |
+                    ty::Closure(def_id, ..) |
+                    ty::Generator(def_id, ..) |
+                    ty::Opaque(def_id, ..) => {
+                        self.infcx.tcx.program_clauses_for(def_id)
+                    }
+
+                    // Artificially trigger an ambiguity.
+                    ty::Infer(..) => {
+                        let tcx = self.infcx.tcx;
+                        let types = [tcx.types.i32, tcx.types.u32, tcx.types.f32, tcx.types.f64];
+                        let clauses = types.iter()
+                            .cloned()
+                            .map(|ty| ProgramClause {
+                                goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
+                                hypotheses: ty::List::empty(),
+                                category: ProgramClauseCategory::WellFormed,
+                            })
+                            .map(|clause| Clause::Implies(clause));
+                        tcx.mk_clauses(clauses)
+                    }
+
+                    ty::GeneratorWitness(..) |
+                    ty::UnnormalizedProjection(..) |
+                    ty::Bound(..) => {
+                        bug!("unexpected type {:?}", ty)
+                    }
+                };
+
+                clauses.into_iter()
+                    .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
+                    .cloned()
+                    .collect()
+            }
+
+            DomainGoal::FromEnv(FromEnv::Trait(..)) => {
+                // These come from:
+                // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
+                // * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
+                // * implied bounds from assoc type defs (rules `Implied-Trait-From-AssocTy`,
+                //   `Implied-Bound-From-AssocTy` and `Implied-WC-From-AssocTy`)
+
+                // All of these rules are computed in the environment.
+                vec![]
+            }
+
+            DomainGoal::FromEnv(FromEnv::Ty(..)) => {
+                // There are no `FromEnv::Ty(..) :- ...` rules (this predicate only
+                // comes from the environment).
+                vec![]
+            }
+
+            DomainGoal::Normalize(projection_predicate) => {
+                // These come from -- assoc ty values (rule `Normalize-From-Impl`).
+                let mut clauses = vec![];
+
+                assemble_clauses_from_assoc_ty_values(
+                    self.infcx.tcx,
+                    projection_predicate.projection_ty.trait_ref(self.infcx.tcx).def_id,
+                    &mut clauses
+                );
+
+                clauses
+            }
+        };
+
+        debug!("program_clauses: clauses = {:?}", clauses);
+        debug!("program_clauses: adding clauses from environment = {:?}", environment);
+
+        let mut _orig_query_values = OriginalQueryValues::default();
+        let canonical_environment = self.infcx.canonicalize_query(
+            environment,
+            &mut _orig_query_values
+        ).value;
+        let env_clauses = self.infcx.tcx.program_clauses_for_env(canonical_environment);
+
+        debug!("program_clauses: env_clauses = {:?}", env_clauses);
+
+        clauses.extend(env_clauses.into_iter().cloned());
+        clauses.extend(environment.clauses.iter().cloned());
+        clauses
+    }
+}
diff --git a/src/librustc_traits/chalk_context/program_clauses/primitive.rs b/src/librustc_traits/chalk_context/program_clauses/primitive.rs
new file mode 100644 (file)
index 0000000..fc6d409
--- /dev/null
@@ -0,0 +1,204 @@
+use rustc::traits::{
+    WellFormed,
+    DomainGoal,
+    GoalKind,
+    Clause,
+    Clauses,
+    ProgramClause,
+    ProgramClauseCategory,
+};
+use rustc::ty;
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc_target::spec::abi;
+use crate::lowering::Lower;
+use crate::generic_types;
+use std::iter;
+
+crate fn wf_clause_for_raw_ptr<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    mutbl: hir::Mutability
+) -> Clauses<'tcx> {
+    let ptr_ty = generic_types::raw_ptr(tcx, mutbl);
+
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)),
+        hypotheses: ty::List::empty(),
+        category: ProgramClauseCategory::WellFormed,
+    };
+    let wf_clause = Clause::Implies(wf_clause);
+
+    // `forall<T> { WellFormed(*const T). }`
+    tcx.mk_clauses(iter::once(wf_clause))
+}
+
+crate fn wf_clause_for_fn_ptr<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    arity_and_output: usize,
+    variadic: bool,
+    unsafety: hir::Unsafety,
+    abi: abi::Abi
+) -> Clauses<'tcx> {
+    let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, variadic, unsafety, abi);
+
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)),
+        hypotheses: ty::List::empty(),
+        category: ProgramClauseCategory::WellFormed,
+    };
+    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
+
+    // `forall <T1, ..., Tn+1> { WellFormed(for<> fn(T1, ..., Tn) -> Tn+1). }`
+    // where `n + 1` == `arity_and_output`
+    tcx.mk_clauses(iter::once(wf_clause))
+}
+
+crate fn wf_clause_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> {
+    let ty = generic_types::bound(tcx, 0);
+    let slice_ty = tcx.mk_slice(ty);
+
+    let sized_trait = match tcx.lang_items().sized_trait() {
+        Some(def_id) => def_id,
+        None => return ty::List::empty(),
+    };
+    let sized_implemented = ty::TraitRef {
+        def_id: sized_trait,
+        substs: tcx.mk_substs_trait(ty, ty::List::empty()),
+    };
+    let sized_implemented: DomainGoal<'_> = ty::TraitPredicate {
+        trait_ref: sized_implemented
+    }.lower();
+
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(slice_ty)),
+        hypotheses: tcx.mk_goals(
+            iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))
+        ),
+        category: ProgramClauseCategory::WellFormed,
+    };
+    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
+
+    // `forall<T> { WellFormed([T]) :- Implemented(T: Sized). }`
+    tcx.mk_clauses(iter::once(wf_clause))
+}
+
+crate fn wf_clause_for_array<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    length: &'tcx ty::Const<'tcx>
+) -> Clauses<'tcx> {
+    let ty = generic_types::bound(tcx, 0);
+    let array_ty = tcx.mk_ty(ty::Array(ty, length));
+
+    let sized_trait = match tcx.lang_items().sized_trait() {
+        Some(def_id) => def_id,
+        None => return ty::List::empty(),
+    };
+    let sized_implemented = ty::TraitRef {
+        def_id: sized_trait,
+        substs: tcx.mk_substs_trait(ty, ty::List::empty()),
+    };
+    let sized_implemented: DomainGoal<'_> = ty::TraitPredicate {
+        trait_ref: sized_implemented
+    }.lower();
+
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(array_ty)),
+        hypotheses: tcx.mk_goals(
+            iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))
+        ),
+        category: ProgramClauseCategory::WellFormed,
+    };
+    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
+
+    // `forall<T> { WellFormed([T; length]) :- Implemented(T: Sized). }`
+    tcx.mk_clauses(iter::once(wf_clause))
+}
+
+crate fn wf_clause_for_tuple<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    arity: usize
+) -> Clauses<'tcx> {
+    let type_list = generic_types::type_list(tcx, arity);
+    let tuple_ty = tcx.mk_ty(ty::Tuple(type_list));
+
+    let sized_trait = match tcx.lang_items().sized_trait() {
+        Some(def_id) => def_id,
+        None => return ty::List::empty(),
+    };
+
+    // If `arity == 0` (i.e. the unit type) or `arity == 1`, this list of
+    // hypotheses is actually empty.
+    let sized_implemented = type_list[0 .. std::cmp::max(arity, 1) - 1].iter()
+        .map(|ty| ty::TraitRef {
+            def_id: sized_trait,
+            substs: tcx.mk_substs_trait(*ty, ty::List::empty()),
+        })
+        .map(|trait_ref| ty::TraitPredicate { trait_ref })
+        .map(|predicate| predicate.lower());
+
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(tuple_ty)),
+        hypotheses: tcx.mk_goals(
+            sized_implemented.map(|domain_goal| {
+                tcx.mk_goal(GoalKind::DomainGoal(domain_goal))
+            })
+        ),
+        category: ProgramClauseCategory::WellFormed,
+    };
+    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
+
+    // ```
+    // forall<T1, ..., Tn-1, Tn> {
+    //     WellFormed((T1, ..., Tn)) :-
+    //         Implemented(T1: Sized),
+    //         ...
+    //         Implemented(Tn-1: Sized).
+    // }
+    // ```
+    tcx.mk_clauses(iter::once(wf_clause))
+}
+
+crate fn wf_clause_for_ref<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    mutbl: hir::Mutability
+) -> Clauses<'tcx> {
+    let region = tcx.mk_region(
+        ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
+    );
+    let ty = generic_types::bound(tcx, 1);
+    let ref_ty = tcx.mk_ref(region, ty::TypeAndMut {
+        ty,
+        mutbl,
+    });
+
+    let outlives: DomainGoal<'_> = ty::OutlivesPredicate(ty, region).lower();
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)),
+        hypotheses: tcx.mk_goals(
+            iter::once(tcx.mk_goal(outlives.into_goal()))
+        ),
+        category: ProgramClauseCategory::WellFormed,
+    };
+    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
+
+    // `forall<'a, T> { WellFormed(&'a T) :- Outlives(T: 'a). }`
+    tcx.mk_clauses(iter::once(wf_clause))
+}
+
+crate fn wf_clause_for_fn_def<'tcx>(
+    tcx: ty::TyCtxt<'_, '_, 'tcx>,
+    def_id: DefId
+) -> Clauses<'tcx> {
+    let fn_def = generic_types::fn_def(tcx, def_id);
+
+    let wf_clause = ProgramClause {
+        goal: DomainGoal::WellFormed(WellFormed::Ty(fn_def)),
+        hypotheses: ty::List::empty(),
+        category: ProgramClauseCategory::WellFormed,
+    };
+    let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
+
+    // `forall <T1, ..., Tn+1> { WellFormed(fn some_fn(T1, ..., Tn) -> Tn+1). }`
+    // where `def_id` maps to the `some_fn` function definition
+    tcx.mk_clauses(iter::once(wf_clause))
+}