rust/compiler/rustc_traits/src/chalk/mod.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

173 lines
7.8 KiB
Rust
Raw Normal View History

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
pub(crate) mod db;
pub(crate) mod lowering;
2020-03-03 11:25:03 -05:00
use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
use rustc_middle::traits::ChalkRustInterner;
use rustc_middle::ty::query::Providers;
2023-01-17 03:27:48 +00:00
use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitable};
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;
use crate::chalk::lowering::LowerInto;
use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector, ReverseParamsSubstitutor};
2020-03-03 11:25:03 -05:00
use chalk_solve::Solution;
pub(crate) fn provide(p: &mut Providers) {
2020-03-03 11:25:03 -05:00
*p = Providers { evaluate_goal, ..*p };
}
pub(crate) fn evaluate_goal<'tcx>(
2020-03-03 11:25:03 -05:00
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 mut params_substitutor =
2020-08-15 18:04:11 -04:00
ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
let obligation = obligation.fold_with(&mut params_substitutor);
2023-01-17 03:27:48 +00:00
let params = params_substitutor.params;
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(
interner,
2020-03-03 11:25:03 -05:00
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() },
),
2022-01-07 09:13:00 -08:00
CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
CanonicalVarKind::PlaceholderConst(_pc, _ty) => unimplemented!(),
2020-03-03 11:25:03 -05:00
}),
),
value: obligation.value.lower_into(interner),
2020-03-03 11:25:03 -05:00
},
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);
let db = ChalkRustIrDatabase { interner };
debug!(?lowered_goal);
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;
let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
2023-01-25 18:04:57 +00:00
let var_values = tcx.mk_substs(
subst
.as_slice(interner)
.iter()
.map(|p| p.lower_into(interner).fold_with(&mut reverse_param_substitutor)),
);
2021-01-01 13:44:31 -05:00
let variables: Vec<_> = binders
.iter(interner)
2021-01-01 13:44:31 -05:00
.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),
),
2022-01-07 09:13:00 -08:00
// FIXME(compiler-errors): We don't currently have a way of turning
// a Chalk ty back into a rustc ty, right?
chalk_ir::VariableKind::Const(_) => todo!(),
2021-01-01 13:44:31 -05:00
};
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,
opaque_types: vec![],
2020-03-03 11:25:03 -05:00
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 {
2023-01-25 18:04:57 +00:00
var_values: CanonicalVarValues::dummy(),
2020-03-03 11:25:03 -05:00
region_constraints: QueryRegionConstraints::default(),
certainty: Certainty::Ambiguous,
opaque_types: vec![],
2020-03-03 11:25:03 -05:00
value: (),
},
};
&*tcx.arena.alloc(sol)
}
}
}
})
.ok_or(traits::query::NoSolution)
}