1 //! Calls `chalk-solve` to solve a `ty::Predicate`
3 //! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into
4 //! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution.
9 use rustc_data_structures::fx::FxHashMap;
11 use rustc_index::vec::IndexVec;
13 use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
14 use rustc_middle::traits::ChalkRustInterner;
15 use rustc_middle::ty::query::Providers;
16 use rustc_middle::ty::subst::GenericArg;
17 use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable};
19 use rustc_infer::infer::canonical::{
20 Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
22 use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
24 use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
25 use crate::chalk::lowering::{
26 LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor,
29 use chalk_solve::Solution;
31 crate fn provide(p: &mut Providers) {
32 *p = Providers { evaluate_goal, ..*p };
35 crate fn evaluate_goal<'tcx>(
37 obligation: CanonicalChalkEnvironmentAndGoal<'tcx>,
38 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> {
39 let interner = ChalkRustInterner { tcx };
41 // Chalk doesn't have a notion of `Params`, so instead we use placeholders.
42 let mut placeholders_collector = PlaceholdersCollector::new();
43 obligation.visit_with(&mut placeholders_collector);
45 let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
46 universe: ty::UniverseIndex::ROOT,
47 name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1),
50 let mut params_substitutor =
51 ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
52 let obligation = obligation.fold_with(&mut params_substitutor);
53 // FIXME(chalk): we really should be substituting these back in the solution
54 let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
56 let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
57 let obligation = obligation.fold_with(&mut regions_substitutor);
59 let max_universe = obligation.max_universe.index();
61 let lowered_goal: chalk_ir::UCanonical<
62 chalk_ir::InEnvironment<chalk_ir::Goal<ChalkRustInterner<'tcx>>>,
63 > = chalk_ir::UCanonical {
64 canonical: chalk_ir::Canonical {
65 binders: chalk_ir::CanonicalVarKinds::from_iter(
67 obligation.variables.iter().map(|v| match v.kind {
68 CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(),
69 CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(),
70 CanonicalVarKind::Ty(ty) => match ty {
71 CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new(
72 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
73 chalk_ir::UniverseIndex { counter: ui.index() },
75 CanonicalTyVarKind::Int => chalk_ir::WithKind::new(
76 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Integer),
77 chalk_ir::UniverseIndex::root(),
79 CanonicalTyVarKind::Float => chalk_ir::WithKind::new(
80 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Float),
81 chalk_ir::UniverseIndex::root(),
84 CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new(
85 chalk_ir::VariableKind::Lifetime,
86 chalk_ir::UniverseIndex { counter: ui.index() },
88 CanonicalVarKind::Const(_ui) => unimplemented!(),
89 CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
92 value: obligation.value.lower_into(&interner),
94 universes: max_universe + 1,
97 use chalk_solve::Solver;
98 let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
99 let db = ChalkRustIrDatabase { interner, reempty_placeholder };
100 let solution = solver.solve(&db, &lowered_goal);
101 debug!(?obligation, ?solution, "evaluate goal");
103 // Ideally, the code to convert *back* to rustc types would live close to
104 // the code to convert *from* rustc types. Right now though, we don't
105 // really need this and so it's really minimal.
106 // Right now, we also treat a `Unique` solution the same as
107 // `Ambig(Definite)`. This really isn't right.
108 let make_solution = |subst: chalk_ir::Substitution<_>,
109 binders: chalk_ir::CanonicalVarKinds<_>| {
110 use rustc_middle::infer::canonical::CanonicalVarInfo;
112 let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
113 subst.as_slice(&interner).iter().for_each(|p| {
114 var_values.push(p.lower_into(&interner));
116 let variables: Vec<_> = binders
119 let kind = match var.kind {
120 chalk_ir::VariableKind::Ty(ty_kind) => CanonicalVarKind::Ty(match ty_kind {
121 chalk_ir::TyVariableKind::General => CanonicalTyVarKind::General(
122 ty::UniverseIndex::from_usize(var.skip_kind().counter),
124 chalk_ir::TyVariableKind::Integer => CanonicalTyVarKind::Int,
125 chalk_ir::TyVariableKind::Float => CanonicalTyVarKind::Float,
127 chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
128 ty::UniverseIndex::from_usize(var.skip_kind().counter),
130 chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
131 ty::UniverseIndex::from_usize(var.skip_kind().counter),
134 CanonicalVarInfo { kind }
138 binders.iter(&interner).map(|v| v.skip_kind().counter).max().unwrap_or(0);
139 let sol = Canonical {
140 max_universe: ty::UniverseIndex::from_usize(max_universe),
141 variables: tcx.intern_canonical_var_infos(&variables),
142 value: QueryResponse {
143 var_values: CanonicalVarValues { var_values },
144 region_constraints: QueryRegionConstraints::default(),
145 certainty: Certainty::Proven,
153 Solution::Unique(subst) => {
154 // FIXME(chalk): handle constraints
155 make_solution(subst.value.subst, subst.binders)
157 Solution::Ambig(guidance) => {
159 chalk_solve::Guidance::Definite(subst) => {
160 make_solution(subst.value, subst.binders)
162 chalk_solve::Guidance::Suggested(_) => unimplemented!(),
163 chalk_solve::Guidance::Unknown => {
164 // chalk_fulfill doesn't use the var_values here, so
165 // let's just ignore that
166 let sol = Canonical {
167 max_universe: ty::UniverseIndex::from_usize(0),
168 variables: obligation.variables,
169 value: QueryResponse {
170 var_values: CanonicalVarValues { var_values: IndexVec::new() }
172 region_constraints: QueryRegionConstraints::default(),
173 certainty: Certainty::Ambiguous,
177 &*tcx.arena.alloc(sol)
182 .ok_or(traits::query::NoSolution)