2020-03-03 11:25:03 -05:00
|
|
|
//! Calls `chalk-solve` to solve a `ty::Predicate`
|
|
|
|
//!
|
2020-09-01 17:58:34 +02:00
|
|
|
//! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into
|
|
|
|
//! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution.
|
2020-03-03 11:25:03 -05:00
|
|
|
|
|
|
|
crate mod db;
|
|
|
|
crate mod lowering;
|
|
|
|
|
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
|
|
|
|
|
|
|
use rustc_index::vec::IndexVec;
|
|
|
|
|
|
|
|
use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
|
|
|
|
use rustc_middle::traits::ChalkRustInterner;
|
|
|
|
use rustc_middle::ty::query::Providers;
|
|
|
|
use rustc_middle::ty::subst::GenericArg;
|
2020-08-04 22:28:59 -04:00
|
|
|
use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable};
|
2020-03-03 11:25:03 -05:00
|
|
|
|
|
|
|
use rustc_infer::infer::canonical::{
|
|
|
|
Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
|
|
|
|
};
|
2020-09-01 17:58:34 +02:00
|
|
|
use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
|
2020-03-03 11:25:03 -05:00
|
|
|
|
|
|
|
use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
|
2020-08-04 22:28:59 -04:00
|
|
|
use crate::chalk::lowering::{
|
|
|
|
LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor,
|
|
|
|
};
|
2020-03-03 11:25:03 -05:00
|
|
|
|
|
|
|
use chalk_solve::Solution;
|
|
|
|
|
2020-07-05 23:00:14 +03:00
|
|
|
crate fn provide(p: &mut Providers) {
|
2020-03-03 11:25:03 -05:00
|
|
|
*p = Providers { evaluate_goal, ..*p };
|
|
|
|
}
|
|
|
|
|
|
|
|
crate fn evaluate_goal<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2020-09-01 17:58:34 +02:00
|
|
|
obligation: CanonicalChalkEnvironmentAndGoal<'tcx>,
|
2020-03-03 11:25:03 -05:00
|
|
|
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> {
|
|
|
|
let interner = ChalkRustInterner { tcx };
|
|
|
|
|
|
|
|
// Chalk doesn't have a notion of `Params`, so instead we use placeholders.
|
2020-08-04 22:28:59 -04:00
|
|
|
let mut placeholders_collector = PlaceholdersCollector::new();
|
|
|
|
obligation.visit_with(&mut placeholders_collector);
|
|
|
|
|
|
|
|
let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
|
|
|
|
universe: ty::UniverseIndex::ROOT,
|
2020-12-18 13:24:55 -05:00
|
|
|
name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1),
|
2020-08-04 22:28:59 -04:00
|
|
|
}));
|
|
|
|
|
|
|
|
let mut params_substitutor =
|
2020-08-15 18:04:11 -04:00
|
|
|
ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
|
2021-05-19 15:03:43 +02:00
|
|
|
let obligation = obligation.fold_with(&mut params_substitutor).into_ok();
|
2020-08-15 18:04:11 -04:00
|
|
|
// FIXME(chalk): we really should be substituting these back in the solution
|
2020-03-03 11:25:03 -05:00
|
|
|
let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
|
2020-08-04 22:28:59 -04:00
|
|
|
|
2020-10-03 20:45:12 -04:00
|
|
|
let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
|
2021-05-19 15:03:43 +02:00
|
|
|
let obligation = obligation.fold_with(&mut regions_substitutor).into_ok();
|
2020-08-04 22:28:59 -04:00
|
|
|
|
2020-03-03 11:25:03 -05:00
|
|
|
let max_universe = obligation.max_universe.index();
|
|
|
|
|
2020-08-15 18:04:11 -04:00
|
|
|
let lowered_goal: chalk_ir::UCanonical<
|
2020-03-03 11:25:03 -05:00
|
|
|
chalk_ir::InEnvironment<chalk_ir::Goal<ChalkRustInterner<'tcx>>>,
|
|
|
|
> = chalk_ir::UCanonical {
|
|
|
|
canonical: chalk_ir::Canonical {
|
2020-08-04 18:35:37 -04:00
|
|
|
binders: chalk_ir::CanonicalVarKinds::from_iter(
|
2020-03-03 11:25:03 -05:00
|
|
|
&interner,
|
|
|
|
obligation.variables.iter().map(|v| match v.kind {
|
|
|
|
CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(),
|
|
|
|
CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(),
|
|
|
|
CanonicalVarKind::Ty(ty) => match ty {
|
2020-05-26 20:19:19 -04:00
|
|
|
CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new(
|
2020-10-28 19:57:56 +00:00
|
|
|
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
|
2020-05-26 20:19:19 -04:00
|
|
|
chalk_ir::UniverseIndex { counter: ui.index() },
|
|
|
|
),
|
|
|
|
CanonicalTyVarKind::Int => chalk_ir::WithKind::new(
|
2020-10-28 19:57:56 +00:00
|
|
|
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Integer),
|
2020-05-26 20:19:19 -04:00
|
|
|
chalk_ir::UniverseIndex::root(),
|
|
|
|
),
|
|
|
|
CanonicalTyVarKind::Float => chalk_ir::WithKind::new(
|
2020-10-28 19:57:56 +00:00
|
|
|
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Float),
|
2020-05-26 20:19:19 -04:00
|
|
|
chalk_ir::UniverseIndex::root(),
|
|
|
|
),
|
2020-03-03 11:25:03 -05:00
|
|
|
},
|
2020-05-26 20:19:19 -04:00
|
|
|
CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new(
|
|
|
|
chalk_ir::VariableKind::Lifetime,
|
|
|
|
chalk_ir::UniverseIndex { counter: ui.index() },
|
|
|
|
),
|
2020-03-03 11:25:03 -05:00
|
|
|
CanonicalVarKind::Const(_ui) => unimplemented!(),
|
|
|
|
CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
|
|
|
|
}),
|
|
|
|
),
|
|
|
|
value: obligation.value.lower_into(&interner),
|
|
|
|
},
|
|
|
|
universes: max_universe + 1,
|
|
|
|
};
|
|
|
|
|
2020-08-04 18:35:37 -04:00
|
|
|
use chalk_solve::Solver;
|
|
|
|
let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
|
2020-10-03 20:45:12 -04:00
|
|
|
let db = ChalkRustIrDatabase { interner, reempty_placeholder };
|
2020-10-28 19:57:56 +00:00
|
|
|
let solution = solver.solve(&db, &lowered_goal);
|
2020-12-27 03:22:23 +01:00
|
|
|
debug!(?obligation, ?solution, "evaluate goal");
|
2020-03-03 11:25:03 -05:00
|
|
|
|
|
|
|
// Ideally, the code to convert *back* to rustc types would live close to
|
|
|
|
// the code to convert *from* rustc types. Right now though, we don't
|
|
|
|
// really need this and so it's really minimal.
|
|
|
|
// Right now, we also treat a `Unique` solution the same as
|
|
|
|
// `Ambig(Definite)`. This really isn't right.
|
2021-01-01 13:44:31 -05:00
|
|
|
let make_solution = |subst: chalk_ir::Substitution<_>,
|
|
|
|
binders: chalk_ir::CanonicalVarKinds<_>| {
|
|
|
|
use rustc_middle::infer::canonical::CanonicalVarInfo;
|
|
|
|
|
2020-03-03 11:25:03 -05:00
|
|
|
let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
|
2020-08-15 18:04:11 -04:00
|
|
|
subst.as_slice(&interner).iter().for_each(|p| {
|
2020-08-04 22:28:59 -04:00
|
|
|
var_values.push(p.lower_into(&interner));
|
2020-03-03 11:25:03 -05:00
|
|
|
});
|
2021-01-01 13:44:31 -05:00
|
|
|
let variables: Vec<_> = binders
|
|
|
|
.iter(&interner)
|
|
|
|
.map(|var| {
|
|
|
|
let kind = match var.kind {
|
|
|
|
chalk_ir::VariableKind::Ty(ty_kind) => CanonicalVarKind::Ty(match ty_kind {
|
|
|
|
chalk_ir::TyVariableKind::General => CanonicalTyVarKind::General(
|
|
|
|
ty::UniverseIndex::from_usize(var.skip_kind().counter),
|
|
|
|
),
|
|
|
|
chalk_ir::TyVariableKind::Integer => CanonicalTyVarKind::Int,
|
|
|
|
chalk_ir::TyVariableKind::Float => CanonicalTyVarKind::Float,
|
|
|
|
}),
|
|
|
|
chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
|
|
|
|
ty::UniverseIndex::from_usize(var.skip_kind().counter),
|
|
|
|
),
|
|
|
|
chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
|
|
|
|
ty::UniverseIndex::from_usize(var.skip_kind().counter),
|
|
|
|
),
|
|
|
|
};
|
|
|
|
CanonicalVarInfo { kind }
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let max_universe =
|
|
|
|
binders.iter(&interner).map(|v| v.skip_kind().counter).max().unwrap_or(0);
|
2020-03-03 11:25:03 -05:00
|
|
|
let sol = Canonical {
|
2021-01-01 13:44:31 -05:00
|
|
|
max_universe: ty::UniverseIndex::from_usize(max_universe),
|
|
|
|
variables: tcx.intern_canonical_var_infos(&variables),
|
2020-03-03 11:25:03 -05:00
|
|
|
value: QueryResponse {
|
|
|
|
var_values: CanonicalVarValues { var_values },
|
|
|
|
region_constraints: QueryRegionConstraints::default(),
|
|
|
|
certainty: Certainty::Proven,
|
|
|
|
value: (),
|
|
|
|
},
|
|
|
|
};
|
2020-08-04 22:28:59 -04:00
|
|
|
tcx.arena.alloc(sol)
|
2020-03-03 11:25:03 -05:00
|
|
|
};
|
|
|
|
solution
|
|
|
|
.map(|s| match s {
|
2020-08-15 18:04:11 -04:00
|
|
|
Solution::Unique(subst) => {
|
2020-03-03 11:25:03 -05:00
|
|
|
// FIXME(chalk): handle constraints
|
2021-01-01 13:44:31 -05:00
|
|
|
make_solution(subst.value.subst, subst.binders)
|
2020-03-03 11:25:03 -05:00
|
|
|
}
|
2020-08-15 18:04:11 -04:00
|
|
|
Solution::Ambig(guidance) => {
|
|
|
|
match guidance {
|
2021-01-01 13:44:31 -05:00
|
|
|
chalk_solve::Guidance::Definite(subst) => {
|
|
|
|
make_solution(subst.value, subst.binders)
|
|
|
|
}
|
2020-03-03 11:25:03 -05:00
|
|
|
chalk_solve::Guidance::Suggested(_) => unimplemented!(),
|
|
|
|
chalk_solve::Guidance::Unknown => {
|
|
|
|
// chalk_fulfill doesn't use the var_values here, so
|
|
|
|
// let's just ignore that
|
|
|
|
let sol = Canonical {
|
|
|
|
max_universe: ty::UniverseIndex::from_usize(0),
|
2021-01-05 16:46:50 +01:00
|
|
|
variables: obligation.variables,
|
2020-03-03 11:25:03 -05:00
|
|
|
value: QueryResponse {
|
|
|
|
var_values: CanonicalVarValues { var_values: IndexVec::new() }
|
|
|
|
.make_identity(tcx),
|
|
|
|
region_constraints: QueryRegionConstraints::default(),
|
|
|
|
certainty: Certainty::Ambiguous,
|
|
|
|
value: (),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
&*tcx.arena.alloc(sol)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.ok_or(traits::query::NoSolution)
|
|
|
|
}
|