From dfcad8250946709e3e28311300057ada7bc98c33 Mon Sep 17 00:00:00 2001 From: scalexm Date: Fri, 23 Nov 2018 22:48:33 +0100 Subject: [PATCH] Add builtin impls for `Sized` in `chalk_context::program_clauses` --- .../chalk_context/program_clauses.rs | 131 ++++++++++++++++++ src/librustc_traits/generic_types.rs | 20 ++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs index e202d29d3fc..b604f140762 100644 --- a/src/librustc_traits/chalk_context/program_clauses.rs +++ b/src/librustc_traits/chalk_context/program_clauses.rs @@ -10,6 +10,7 @@ use rustc::traits::{ 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> +) { + 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::>(); + 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 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> { // * 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` diff --git a/src/librustc_traits/generic_types.rs b/src/librustc_traits/generic_types.rs index 15d6d6c5168..03511e1d76d 100644 --- a/src/librustc_traits/generic_types.rs +++ b/src/librustc_traits/generic_types.rs @@ -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 type_list(tcx: ty::TyCtxt<'_, '_, 'tcx>, arity: usize) -> &'tcx ty::Lis ) } -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)) ); @@ -60,3 +62,19 @@ crate fn _ref_ty(tcx: ty::TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'t 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) +}