Skip to content

Commit

Permalink
Add builtin impls for Sized in chalk_context::program_clauses
Browse files Browse the repository at this point in the history
  • Loading branch information
scalexm committed Dec 27, 2018
1 parent 6f488b9 commit dfcad82
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 1 deletion.
131 changes: 131 additions & 0 deletions src/librustc_traits/chalk_context/program_clauses.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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`
Expand Down
20 changes: 19 additions & 1 deletion 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> {
Expand Down Expand Up @@ -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))
);
Expand All @@ -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)
}

0 comments on commit dfcad82

Please sign in to comment.