]> git.lizzy.rs Git - rust.git/commitdiff
Add builtin impls for `Sized` in `chalk_context::program_clauses`
authorscalexm <alexandre@scalexm.fr>
Fri, 23 Nov 2018 21:48:33 +0000 (22:48 +0100)
committerscalexm <alexandre@scalexm.fr>
Thu, 27 Dec 2018 18:21:16 +0000 (19:21 +0100)
src/librustc_traits/chalk_context/program_clauses.rs
src/librustc_traits/generic_types.rs

index e202d29d3fce3d72c82e5410512ccbaab09af608..b604f140762f43bed87e36baa1e556b2a80e6212 100644 (file)
@@ -10,6 +10,7 @@
     Environment,
 };
 use rustc::ty;
+use rustc::ty::subst::{Substs, Subst};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc_target::spec::abi;
@@ -48,6 +49,126 @@ fn assemble_clauses_from_assoc_ty_values<'tcx>(
     });
 }
 
+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.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 = Substs::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>,
@@ -236,12 +357,22 @@ pub(super) fn program_clauses_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`
index 15d6d6c51682d7b69cde88c5427dfd44529c9d55..03511e1d76d0562cf26fcd1b30046c768a1554d2 100644 (file)
@@ -1,7 +1,9 @@
 //! Utilities for creating generic types with bound vars in place of parameter values.
 
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 use rustc::hir;
+use rustc::hir::def_id::DefId;
 use rustc_target::spec::abi;
 
 crate fn bound(tcx: ty::TyCtxt<'_, '_, 'tcx>, index: u32) -> Ty<'tcx> {
@@ -50,7 +52,7 @@
     )
 }
 
-crate fn _ref_ty(tcx: ty::TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> {
+crate fn ref_ty(tcx: ty::TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> {
     let region = tcx.mk_region(
         ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))
     );
         mutbl,
     })
 }
+
+crate fn fn_def(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> {
+    tcx.mk_ty(ty::FnDef(def_id, Substs::bound_vars_for_item(tcx, def_id)))
+}
+
+crate fn closure(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> {
+    tcx.mk_closure(def_id, ty::ClosureSubsts {
+        substs: Substs::bound_vars_for_item(tcx, def_id),
+    })
+}
+
+crate fn generator(tcx: ty::TyCtxt<'_, '_, 'tcx>, def_id: DefId) -> Ty<'tcx> {
+    tcx.mk_generator(def_id, ty::GeneratorSubsts {
+        substs: Substs::bound_vars_for_item(tcx, def_id),
+    }, hir::GeneratorMovability::Movable)
+}