Rollup merge of #107102 - compiler-errors:new-solver-new-candidats-4, r=lcnr
Implement some more predicates in the new solver
Implement a few more goals. The subtype goal specifically is important, since it's required for this code to compile:
```
fn main() {
let mut x = vec![];
x.push(1i32);
}
```
(I think we emit a subtype goal here because of coercion).
Drive-by: Also implements `--compare-mode=next-solver` -- I've been using this locally a lot to find out what works and what doesn't. I'm also happy to split this out into another PR.
r? `@lcnr`
This commit is contained in:
commit
d022013eb7
7 changed files with 91 additions and 18 deletions
|
|
@ -1,7 +1,7 @@
|
|||
//! Code shared by trait and projection goals for candidate assembly.
|
||||
|
||||
use super::infcx_ext::InferCtxtExt;
|
||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
||||
use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::elaborate_predicates;
|
||||
|
|
@ -148,9 +148,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
if goal.predicate.self_ty().is_ty_var() {
|
||||
return vec![Candidate {
|
||||
source: CandidateSource::BuiltinImpl,
|
||||
result: self
|
||||
.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity))
|
||||
.unwrap(),
|
||||
result: self.make_canonical_response(Certainty::AMBIGUOUS).unwrap(),
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
use std::mem;
|
||||
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
|
||||
use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
|
||||
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
|
||||
|
|
@ -26,7 +27,9 @@ use rustc_infer::traits::query::NoSolution;
|
|||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::infer::canonical::Certainty as OldCertainty;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
|
||||
use rustc_middle::ty::{
|
||||
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use crate::traits::ObligationCause;
|
||||
|
|
@ -87,6 +90,8 @@ pub enum Certainty {
|
|||
}
|
||||
|
||||
impl Certainty {
|
||||
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
|
||||
|
||||
/// When proving multiple goals using **AND**, e.g. nested obligations for an impl,
|
||||
/// use this function to unify the certainty of these goals
|
||||
pub fn unify_and(self, other: Certainty) -> Certainty {
|
||||
|
|
@ -243,16 +248,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => {
|
||||
self.compute_region_outlives_goal(Goal { param_env, predicate })
|
||||
}
|
||||
ty::PredicateKind::Subtype(predicate) => {
|
||||
self.compute_subtype_goal(Goal { param_env, predicate })
|
||||
}
|
||||
ty::PredicateKind::Coerce(predicate) => {
|
||||
self.compute_coerce_goal(Goal { param_env, predicate })
|
||||
}
|
||||
ty::PredicateKind::ClosureKind(def_id, substs, kind) => self
|
||||
.compute_closure_kind_goal(Goal {
|
||||
param_env,
|
||||
predicate: (def_id, substs, kind),
|
||||
}),
|
||||
ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS),
|
||||
// FIXME: implement these predicates :)
|
||||
ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ClosureKind(_, _, _)
|
||||
| ty::PredicateKind::Subtype(_)
|
||||
| ty::PredicateKind::Coerce(_)
|
||||
| ty::PredicateKind::ConstEvaluatable(_)
|
||||
| ty::PredicateKind::ConstEquate(_, _)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(_)
|
||||
| ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::Yes),
|
||||
| ty::PredicateKind::ConstEquate(_, _) => {
|
||||
self.make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let kind = self.infcx.replace_bound_vars_with_placeholders(kind);
|
||||
|
|
@ -275,6 +292,58 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
) -> QueryResult<'tcx> {
|
||||
self.make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
fn compute_coerce_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, CoercePredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.compute_subtype_goal(Goal {
|
||||
param_env: goal.param_env,
|
||||
predicate: SubtypePredicate {
|
||||
a_is_expected: false,
|
||||
a: goal.predicate.a,
|
||||
b: goal.predicate.b,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_subtype_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, SubtypePredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
|
||||
// FIXME: Do we want to register a subtype relation between these vars?
|
||||
// That won't actually reflect in the query response, so it seems moot.
|
||||
self.make_canonical_response(Certainty::AMBIGUOUS)
|
||||
} else {
|
||||
self.infcx.probe(|_| {
|
||||
let InferOk { value: (), obligations } = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), goal.param_env)
|
||||
.sub(goal.predicate.a, goal.predicate.b)?;
|
||||
self.evaluate_all_and_make_canonical_response(
|
||||
obligations.into_iter().map(|pred| pred.into()).collect(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_closure_kind_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let (_, substs, expected_kind) = goal.predicate;
|
||||
let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind();
|
||||
|
||||
let Some(found_kind) = found_kind else {
|
||||
return self.make_canonical_response(Certainty::AMBIGUOUS);
|
||||
};
|
||||
if found_kind.extends(expected_kind) {
|
||||
self.make_canonical_response(Certainty::Yes)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::traits::{specialization_graph, translate_substs};
|
|||
use super::assembly::{self, Candidate, CandidateSource};
|
||||
use super::infcx_ext::InferCtxtExt;
|
||||
use super::trait_goals::structural_traits;
|
||||
use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
||||
use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -229,8 +229,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
goal.predicate.def_id(),
|
||||
impl_def_id
|
||||
)? else {
|
||||
let certainty = Certainty::Maybe(MaybeCause::Ambiguity);
|
||||
return ecx.make_canonical_response(trait_ref_certainty.unify_and(certainty));
|
||||
return ecx.make_canonical_response(trait_ref_certainty.unify_and(Certainty::AMBIGUOUS));
|
||||
};
|
||||
|
||||
if !assoc_def.item.defaultness(tcx).has_value() {
|
||||
|
|
@ -382,7 +381,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
.to_predicate(ecx.tcx());
|
||||
Self::consider_assumption(ecx, goal, pred)
|
||||
} else {
|
||||
ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity))
|
||||
ecx.make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::iter;
|
|||
|
||||
use super::assembly::{self, Candidate, CandidateSource};
|
||||
use super::infcx_ext::InferCtxtExt;
|
||||
use super::{Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
|
||||
use super::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
|
|
@ -133,7 +133,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
if goal.predicate.self_ty().has_non_region_infer() {
|
||||
return ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity));
|
||||
return ecx.make_canonical_response(Certainty::AMBIGUOUS);
|
||||
}
|
||||
|
||||
let tcx = ecx.tcx();
|
||||
|
|
@ -171,7 +171,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
.to_predicate(ecx.tcx());
|
||||
Self::consider_assumption(ecx, goal, pred)
|
||||
} else {
|
||||
ecx.make_canonical_response(Certainty::Maybe(MaybeCause::Ambiguity))
|
||||
ecx.make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ pub enum FailMode {
|
|||
pub enum CompareMode {
|
||||
Polonius,
|
||||
Chalk,
|
||||
NextSolver,
|
||||
SplitDwarf,
|
||||
SplitDwarfSingle,
|
||||
}
|
||||
|
|
@ -132,6 +133,7 @@ impl CompareMode {
|
|||
match *self {
|
||||
CompareMode::Polonius => "polonius",
|
||||
CompareMode::Chalk => "chalk",
|
||||
CompareMode::NextSolver => "next-solver",
|
||||
CompareMode::SplitDwarf => "split-dwarf",
|
||||
CompareMode::SplitDwarfSingle => "split-dwarf-single",
|
||||
}
|
||||
|
|
@ -141,6 +143,7 @@ impl CompareMode {
|
|||
match s.as_str() {
|
||||
"polonius" => CompareMode::Polonius,
|
||||
"chalk" => CompareMode::Chalk,
|
||||
"next-solver" => CompareMode::NextSolver,
|
||||
"split-dwarf" => CompareMode::SplitDwarf,
|
||||
"split-dwarf-single" => CompareMode::SplitDwarfSingle,
|
||||
x => panic!("unknown --compare-mode option: {}", x),
|
||||
|
|
|
|||
|
|
@ -710,6 +710,7 @@ impl Config {
|
|||
match self.compare_mode {
|
||||
Some(CompareMode::Polonius) => name == "compare-mode-polonius",
|
||||
Some(CompareMode::Chalk) => name == "compare-mode-chalk",
|
||||
Some(CompareMode::NextSolver) => name == "compare-mode-next-solver",
|
||||
Some(CompareMode::SplitDwarf) => name == "compare-mode-split-dwarf",
|
||||
Some(CompareMode::SplitDwarfSingle) => name == "compare-mode-split-dwarf-single",
|
||||
None => false,
|
||||
|
|
|
|||
|
|
@ -2030,6 +2030,9 @@ impl<'test> TestCx<'test> {
|
|||
Some(CompareMode::Chalk) => {
|
||||
rustc.args(&["-Ztrait-solver=chalk"]);
|
||||
}
|
||||
Some(CompareMode::NextSolver) => {
|
||||
rustc.args(&["-Ztrait-solver=next"]);
|
||||
}
|
||||
Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => {
|
||||
rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue