5 use chalk_engine::fallible::Fallible;
6 use chalk_engine::forest::Forest;
7 use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause, Literal};
8 use rustc::infer::canonical::{
9 Canonical, CanonicalVarValues, Certainty, OriginalQueryValues, QueryRegionConstraints,
12 use rustc::infer::{InferCtxt, LateBoundRegionConversionTime};
14 self, ChalkCanonicalGoal, ChalkContextLift, Clause, DomainGoal, Environment, ExClauseFold,
15 Goal, GoalKind, InEnvironment, QuantifierKind,
17 use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
18 use rustc::ty::query::Providers;
19 use rustc::ty::subst::{GenericArg, GenericArgKind};
20 use rustc::ty::{self, TyCtxt};
21 use rustc_macros::{Lift, TypeFoldable};
22 use rustc_span::DUMMY_SP;
24 use std::fmt::{self, Debug};
25 use std::marker::PhantomData;
29 #[derive(Copy, Clone, Debug)]
30 crate struct ChalkArenas<'tcx> {
31 _phantom: PhantomData<&'tcx ()>,
34 #[derive(Copy, Clone)]
35 crate struct ChalkContext<'tcx> {
36 _arenas: ChalkArenas<'tcx>,
40 #[derive(Copy, Clone)]
41 crate struct ChalkInferenceContext<'cx, 'tcx> {
42 infcx: &'cx InferCtxt<'cx, 'tcx>,
45 #[derive(Copy, Clone, Debug)]
46 crate struct UniverseMap;
48 crate type RegionConstraint<'tcx> = ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>;
50 #[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, Lift)]
51 crate struct ConstrainedSubst<'tcx> {
52 subst: CanonicalVarValues<'tcx>,
53 constraints: Vec<RegionConstraint<'tcx>>,
56 impl context::Context for ChalkArenas<'tcx> {
57 type CanonicalExClause = Canonical<'tcx, ChalkExClause<'tcx>>;
59 type CanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>;
61 // u-canonicalization not yet implemented
62 type UCanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>;
64 type CanonicalConstrainedSubst = Canonical<'tcx, ConstrainedSubst<'tcx>>;
66 // u-canonicalization not yet implemented
67 type UniverseMap = UniverseMap;
69 type Solution = Canonical<'tcx, QueryResponse<'tcx, ()>>;
71 type InferenceNormalizedSubst = CanonicalVarValues<'tcx>;
73 type GoalInEnvironment = InEnvironment<'tcx, Goal<'tcx>>;
75 type RegionConstraint = RegionConstraint<'tcx>;
77 type Substitution = CanonicalVarValues<'tcx>;
79 type Environment = Environment<'tcx>;
81 type Goal = Goal<'tcx>;
83 type DomainGoal = DomainGoal<'tcx>;
85 type BindersGoal = ty::Binder<Goal<'tcx>>;
87 type Parameter = GenericArg<'tcx>;
89 type ProgramClause = Clause<'tcx>;
91 type ProgramClauses = Vec<Clause<'tcx>>;
93 type UnificationResult = UnificationResult<'tcx>;
95 type Variance = ty::Variance;
97 fn goal_in_environment(
98 env: &Environment<'tcx>,
100 ) -> InEnvironment<'tcx, Goal<'tcx>> {
105 impl context::AggregateOps<ChalkArenas<'tcx>> for ChalkContext<'tcx> {
108 root_goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
109 mut simplified_answers: impl context::AnswerStream<ChalkArenas<'tcx>>,
110 ) -> Option<Canonical<'tcx, QueryResponse<'tcx, ()>>> {
111 use chalk_engine::SimplifiedAnswer;
113 debug!("make_solution(root_goal = {:?})", root_goal);
115 if simplified_answers.peek_answer().is_none() {
119 let SimplifiedAnswer { subst: constrained_subst, ambiguous } =
120 simplified_answers.next_answer().unwrap();
122 debug!("make_solution: ambiguous flag = {}", ambiguous);
124 let ambiguous = simplified_answers.peek_answer().is_some() || ambiguous;
126 let solution = constrained_subst.unchecked_map(|cs| match ambiguous {
127 true => QueryResponse {
128 var_values: cs.subst.make_identity(self.tcx),
129 region_constraints: QueryRegionConstraints::default(),
130 certainty: Certainty::Ambiguous,
134 false => QueryResponse {
135 var_values: cs.subst,
136 region_constraints: QueryRegionConstraints::default(),
138 // FIXME: restore this later once we get better at handling regions
139 // region_constraints: cs.constraints
141 // .map(|c| ty::Binder::bind(c))
143 certainty: Certainty::Proven,
148 debug!("make_solution: solution = {:?}", solution);
154 impl context::ContextOps<ChalkArenas<'tcx>> for ChalkContext<'tcx> {
155 /// Returns `true` if this is a coinductive goal: basically proving that an auto trait
156 /// is implemented or proving that a trait reference is well-formed.
157 fn is_coinductive(&self, goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> bool {
158 use rustc::traits::{WellFormed, WhereClause};
160 let mut goal = goal.value.goal;
163 GoalKind::DomainGoal(domain_goal) => match domain_goal {
164 DomainGoal::WellFormed(WellFormed::Trait(..)) => return true,
165 DomainGoal::Holds(WhereClause::Implemented(trait_predicate)) => {
166 return self.tcx.trait_is_auto(trait_predicate.def_id());
171 GoalKind::Quantified(_, bound_goal) => goal = *bound_goal.skip_binder(),
177 /// Creates an inference table for processing a new goal and instantiate that goal
178 /// in that context, returning "all the pieces".
180 /// More specifically: given a u-canonical goal `arg`, creates a
181 /// new inference table `T` and populates it with the universes
182 /// found in `arg`. Then, creates a substitution `S` that maps
183 /// each bound variable in `arg` to a fresh inference variable
187 /// - the substitution `S`,
188 /// - the environment and goal found by substitution `S` into `arg`.
189 fn instantiate_ucanonical_goal<R>(
191 arg: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
192 op: impl context::WithInstantiatedUCanonicalGoal<ChalkArenas<'tcx>, Output = R>,
194 self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, arg, |ref infcx, arg, subst| {
195 let chalk_infcx = &mut ChalkInferenceContext { infcx };
196 op.with(chalk_infcx, subst, arg.environment, arg.goal)
200 fn instantiate_ex_clause<R>(
202 _num_universes: usize,
203 arg: &Canonical<'tcx, ChalkExClause<'tcx>>,
204 op: impl context::WithInstantiatedExClause<ChalkArenas<'tcx>, Output = R>,
206 self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &arg.upcast(), |ref infcx, arg, _| {
207 let chalk_infcx = &mut ChalkInferenceContext { infcx };
208 op.with(chalk_infcx, arg)
212 /// Returns `true` if this solution has no region constraints.
213 fn empty_constraints(ccs: &Canonical<'tcx, ConstrainedSubst<'tcx>>) -> bool {
214 ccs.value.constraints.is_empty()
217 fn inference_normalized_subst_from_ex_clause(
218 canon_ex_clause: &'a Canonical<'tcx, ChalkExClause<'tcx>>,
219 ) -> &'a CanonicalVarValues<'tcx> {
220 &canon_ex_clause.value.subst
223 fn inference_normalized_subst_from_subst(
224 canon_subst: &'a Canonical<'tcx, ConstrainedSubst<'tcx>>,
225 ) -> &'a CanonicalVarValues<'tcx> {
226 &canon_subst.value.subst
230 u_canon: &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
231 ) -> &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> {
235 fn is_trivial_substitution(
236 u_canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
237 canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>,
239 let subst = &canonical_subst.value.subst;
240 assert_eq!(u_canon.variables.len(), subst.var_values.len());
241 subst.var_values.iter_enumerated().all(|(cvar, kind)| match kind.unpack() {
242 GenericArgKind::Lifetime(r) => match r {
243 &ty::ReLateBound(debruijn, br) => {
244 debug_assert_eq!(debruijn, ty::INNERMOST);
245 cvar == br.assert_bound_var()
249 GenericArgKind::Type(ty) => match ty.kind {
250 ty::Bound(debruijn, bound_ty) => {
251 debug_assert_eq!(debruijn, ty::INNERMOST);
256 GenericArgKind::Const(ct) => match ct.val {
257 ty::ConstKind::Bound(debruijn, bound_ct) => {
258 debug_assert_eq!(debruijn, ty::INNERMOST);
266 fn num_universes(canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> usize {
267 canon.max_universe.index() + 1
270 /// Convert a goal G *from* the canonical universes *into* our
271 /// local universes. This will yield a goal G' that is the same
272 /// but for the universes of universally quantified names.
273 fn map_goal_from_canonical(
275 value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
276 ) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> {
277 *value // FIXME universe maps not implemented yet
280 fn map_subst_from_canonical(
282 value: &Canonical<'tcx, ConstrainedSubst<'tcx>>,
283 ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> {
284 value.clone() // FIXME universe maps not implemented yet
288 impl context::InferenceTable<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
289 for ChalkInferenceContext<'cx, 'tcx>
291 fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> {
292 self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal))
295 fn cannot_prove(&self) -> Goal<'tcx> {
296 self.infcx.tcx.mk_goal(GoalKind::CannotProve)
299 fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> {
301 GoalKind::Implies(hypotheses, goal) => {
302 HhGoal::Implies(hypotheses.iter().cloned().collect(), goal)
304 GoalKind::And(left, right) => HhGoal::And(left, right),
305 GoalKind::Not(subgoal) => HhGoal::Not(subgoal),
306 GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d),
307 GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
308 GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
309 GoalKind::Subtype(a, b) => HhGoal::Unify(ty::Variance::Covariant, a.into(), b.into()),
310 GoalKind::CannotProve => HhGoal::CannotProve,
316 env: &Environment<'tcx>,
317 clauses: Vec<Clause<'tcx>>,
318 ) -> Environment<'tcx> {
323 .mk_clauses(env.clauses.iter().cloned().chain(clauses.into_iter())),
328 impl context::TruncateOps<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
329 for ChalkInferenceContext<'cx, 'tcx>
333 _subgoal: &InEnvironment<'tcx, Goal<'tcx>>,
334 ) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
335 None // FIXME we should truncate at some point!
340 _subst: &CanonicalVarValues<'tcx>,
341 ) -> Option<CanonicalVarValues<'tcx>> {
342 None // FIXME we should truncate at some point!
346 impl context::UnificationOps<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
347 for ChalkInferenceContext<'cx, 'tcx>
351 environment: &Environment<'tcx>,
352 goal: &DomainGoal<'tcx>,
353 ) -> Vec<Clause<'tcx>> {
354 self.program_clauses_impl(environment, goal)
357 fn instantiate_binders_universally(&mut self, arg: &ty::Binder<Goal<'tcx>>) -> Goal<'tcx> {
358 self.infcx.replace_bound_vars_with_placeholders(arg).0
361 fn instantiate_binders_existentially(&mut self, arg: &ty::Binder<Goal<'tcx>>) -> Goal<'tcx> {
363 .replace_bound_vars_with_fresh_vars(
365 LateBoundRegionConversionTime::HigherRankedType,
371 fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box<dyn Debug + 'v> {
372 let string = format!("{:?}", self.infcx.resolve_vars_if_possible(value));
376 fn canonicalize_goal(
378 value: &InEnvironment<'tcx, Goal<'tcx>>,
379 ) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> {
380 let mut _orig_values = OriginalQueryValues::default();
381 self.infcx.canonicalize_query(value, &mut _orig_values)
384 fn canonicalize_ex_clause(
386 value: &ChalkExClause<'tcx>,
387 ) -> Canonical<'tcx, ChalkExClause<'tcx>> {
388 self.infcx.canonicalize_response(value)
391 fn canonicalize_constrained_subst(
393 subst: CanonicalVarValues<'tcx>,
394 constraints: Vec<RegionConstraint<'tcx>>,
395 ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> {
396 self.infcx.canonicalize_response(&ConstrainedSubst { subst, constraints })
399 fn u_canonicalize_goal(
401 value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
402 ) -> (Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, UniverseMap) {
403 (value.clone(), UniverseMap)
408 _value: &InEnvironment<'tcx, Goal<'tcx>>,
409 ) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
410 panic!("goal inversion not yet implemented")
415 environment: &Environment<'tcx>,
416 variance: ty::Variance,
417 a: &GenericArg<'tcx>,
418 b: &GenericArg<'tcx>,
419 ) -> Fallible<UnificationResult<'tcx>> {
420 self.infcx.commit_if_ok(|_| {
421 unify(self.infcx, *environment, variance, a, b)
422 .map_err(|_| chalk_engine::fallible::NoSolution)
426 fn sink_answer_subset(
428 value: &Canonical<'tcx, ConstrainedSubst<'tcx>>,
429 ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> {
433 fn lift_delayed_literal(
435 value: DelayedLiteral<ChalkArenas<'tcx>>,
436 ) -> DelayedLiteral<ChalkArenas<'tcx>> {
437 match self.infcx.tcx.lift(&value) {
438 Some(literal) => literal,
439 None => bug!("cannot lift {:?}", value),
445 result: UnificationResult<'tcx>,
446 ex_clause: &mut ChalkExClause<'tcx>,
448 into_ex_clause(result, ex_clause);
452 crate fn into_ex_clause(result: UnificationResult<'tcx>, ex_clause: &mut ChalkExClause<'tcx>) {
453 ex_clause.subgoals.extend(result.goals.into_iter().map(Literal::Positive));
455 // FIXME: restore this later once we get better at handling regions
456 let _ = result.constraints.len(); // trick `-D dead-code`
457 // ex_clause.constraints.extend(result.constraints);
460 type ChalkHhGoal<'tcx> = HhGoal<ChalkArenas<'tcx>>;
462 type ChalkExClause<'tcx> = ExClause<ChalkArenas<'tcx>>;
464 impl Debug for ChalkContext<'tcx> {
465 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
466 write!(f, "ChalkContext")
470 impl Debug for ChalkInferenceContext<'cx, 'tcx> {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 write!(f, "ChalkInferenceContext")
476 impl ChalkContextLift<'tcx> for ChalkArenas<'a> {
477 type LiftedExClause = ChalkExClause<'tcx>;
478 type LiftedDelayedLiteral = DelayedLiteral<ChalkArenas<'tcx>>;
479 type LiftedLiteral = Literal<ChalkArenas<'tcx>>;
481 fn lift_ex_clause_to_tcx(
482 ex_clause: &ChalkExClause<'a>,
484 ) -> Option<Self::LiftedExClause> {
486 subst: tcx.lift(&ex_clause.subst)?,
487 delayed_literals: tcx.lift(&ex_clause.delayed_literals)?,
488 constraints: tcx.lift(&ex_clause.constraints)?,
489 subgoals: tcx.lift(&ex_clause.subgoals)?,
493 fn lift_delayed_literal_to_tcx(
494 literal: &DelayedLiteral<ChalkArenas<'a>>,
496 ) -> Option<Self::LiftedDelayedLiteral> {
498 DelayedLiteral::CannotProve(()) => DelayedLiteral::CannotProve(()),
499 DelayedLiteral::Negative(index) => DelayedLiteral::Negative(*index),
500 DelayedLiteral::Positive(index, subst) => {
501 DelayedLiteral::Positive(*index, tcx.lift(subst)?)
506 fn lift_literal_to_tcx(
507 literal: &Literal<ChalkArenas<'a>>,
509 ) -> Option<Self::LiftedLiteral> {
511 Literal::Negative(goal) => Literal::Negative(tcx.lift(goal)?),
512 Literal::Positive(goal) => Literal::Positive(tcx.lift(goal)?),
517 impl ExClauseFold<'tcx> for ChalkArenas<'tcx> {
518 fn fold_ex_clause_with<F: TypeFolder<'tcx>>(
519 ex_clause: &ChalkExClause<'tcx>,
521 ) -> ChalkExClause<'tcx> {
523 subst: ex_clause.subst.fold_with(folder),
524 delayed_literals: ex_clause.delayed_literals.fold_with(folder),
525 constraints: ex_clause.constraints.fold_with(folder),
526 subgoals: ex_clause.subgoals.fold_with(folder),
530 fn visit_ex_clause_with<V: TypeVisitor<'tcx>>(
531 ex_clause: &ExClause<Self>,
534 let ExClause { subst, delayed_literals, constraints, subgoals } = ex_clause;
535 subst.visit_with(visitor)
536 || delayed_literals.visit_with(visitor)
537 || constraints.visit_with(visitor)
538 || subgoals.visit_with(visitor)
542 trait Upcast<'tcx>: 'tcx {
545 fn upcast(&self) -> Self::Upcasted;
548 impl<'tcx> Upcast<'tcx> for DelayedLiteral<ChalkArenas<'tcx>> {
549 type Upcasted = DelayedLiteral<ChalkArenas<'tcx>>;
551 fn upcast(&self) -> Self::Upcasted {
553 &DelayedLiteral::CannotProve(..) => DelayedLiteral::CannotProve(()),
554 &DelayedLiteral::Negative(index) => DelayedLiteral::Negative(index),
555 DelayedLiteral::Positive(index, subst) => {
556 DelayedLiteral::Positive(*index, subst.clone())
562 impl<'tcx> Upcast<'tcx> for Literal<ChalkArenas<'tcx>> {
563 type Upcasted = Literal<ChalkArenas<'tcx>>;
565 fn upcast(&self) -> Self::Upcasted {
567 &Literal::Negative(goal) => Literal::Negative(goal),
568 &Literal::Positive(goal) => Literal::Positive(goal),
573 impl<'tcx> Upcast<'tcx> for ExClause<ChalkArenas<'tcx>> {
574 type Upcasted = ExClause<ChalkArenas<'tcx>>;
576 fn upcast(&self) -> Self::Upcasted {
578 subst: self.subst.clone(),
579 delayed_literals: self.delayed_literals.iter().map(|l| l.upcast()).collect(),
580 constraints: self.constraints.clone(),
581 subgoals: self.subgoals.iter().map(|g| g.upcast()).collect(),
586 impl<'tcx, T> Upcast<'tcx> for Canonical<'tcx, T>
590 type Upcasted = Canonical<'tcx, T::Upcasted>;
592 fn upcast(&self) -> Self::Upcasted {
594 max_universe: self.max_universe,
595 value: self.value.upcast(),
596 variables: self.variables,
601 crate fn provide(p: &mut Providers<'_>) {
602 *p = Providers { evaluate_goal, ..*p };
605 crate fn evaluate_goal<'tcx>(
607 goal: ChalkCanonicalGoal<'tcx>,
608 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> {
609 use crate::lowering::Lower;
610 use rustc::traits::WellFormed;
612 let goal = goal.unchecked_map(|goal| InEnvironment {
613 environment: goal.environment,
614 goal: match goal.goal {
615 ty::Predicate::WellFormed(ty) => {
616 tcx.mk_goal(GoalKind::DomainGoal(DomainGoal::WellFormed(WellFormed::Ty(ty))))
619 ty::Predicate::Subtype(predicate) => tcx.mk_goal(GoalKind::Quantified(
620 QuantifierKind::Universal,
621 predicate.map_bound(|pred| tcx.mk_goal(GoalKind::Subtype(pred.a, pred.b))),
624 other => tcx.mk_goal(GoalKind::from_poly_domain_goal(other.lower(), tcx)),
628 debug!("evaluate_goal(goal = {:?})", goal);
630 let context = ChalkContext { _arenas: ChalkArenas { _phantom: PhantomData }, tcx };
632 let mut forest = Forest::new(context);
633 let solution = forest.solve(&goal);
635 debug!("evaluate_goal: solution = {:?}", solution);
637 solution.map(|ok| Ok(&*tcx.arena.alloc(ok))).unwrap_or(Err(traits::query::NoSolution))