Auto merge of #69247 - CAD97:remove-chalk, r=nikomatsakis
Remove experimental chalk option As suggested by @nikomatsakis [here](https://github.com/rust-lang/rust/pull/68807#issuecomment-583339932). The current version of chalk used by the experimental `-Zchalk` flag is [v0.9.0, which is over a year old](https://crates.io/crates/chalk-engine). Since v0.9.0, chalk has seen [a lot of further development](https://github.com/rust-lang/chalk/compare/41dfe13...master), and the intent is to eventually upgrade rustc to use a more recent chalk. However, it will take a decent chunk of effort to upgrade the current experimental chalk support, and it is currently [blocking at least some PRs](https://github.com/rust-lang/rust/pull/68807) due to chalk:0.9.0's use of unstable features. So for the interim until the next chalk release and experimental rustc integration, we remove the chalk-specific code from rustc.
This commit is contained in:
commit
9381e8178b
53 changed files with 20 additions and 2860 deletions
21
Cargo.lock
21
Cargo.lock
|
@ -419,25 +419,6 @@ dependencies = [
|
|||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chalk-engine"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a"
|
||||
dependencies = [
|
||||
"chalk-macros",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chalk-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.6"
|
||||
|
@ -3110,7 +3091,6 @@ dependencies = [
|
|||
"backtrace",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"chalk-engine",
|
||||
"jobserver",
|
||||
"log",
|
||||
"measureme",
|
||||
|
@ -4144,7 +4124,6 @@ checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee"
|
|||
name = "rustc_traits"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"chalk-engine",
|
||||
"log",
|
||||
"rustc",
|
||||
"rustc_ast",
|
||||
|
|
|
@ -33,7 +33,6 @@ rustc_span = { path = "../librustc_span" }
|
|||
backtrace = "0.3.40"
|
||||
parking_lot = "0.9"
|
||||
byteorder = { version = "1.3" }
|
||||
chalk-engine = { version = "0.9.0", default-features=false }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
measureme = "0.7.1"
|
||||
rustc_session = { path = "../librustc_session" }
|
||||
|
|
|
@ -1130,16 +1130,6 @@ rustc_queries! {
|
|||
desc { "evaluating trait selection obligation `{}`", goal.value.value }
|
||||
}
|
||||
|
||||
query evaluate_goal(
|
||||
goal: traits::ChalkCanonicalGoal<'tcx>
|
||||
) -> Result<
|
||||
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
|
||||
NoSolution
|
||||
> {
|
||||
no_force
|
||||
desc { "evaluating trait selection obligation `{}`", goal.value.goal }
|
||||
}
|
||||
|
||||
/// Do not call this query directly: part of the `Eq` type-op
|
||||
query type_op_ascribe_user_type(
|
||||
goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>
|
||||
|
|
|
@ -7,9 +7,7 @@ pub mod select;
|
|||
pub mod specialization_graph;
|
||||
mod structural_impls;
|
||||
|
||||
use crate::infer::canonical::Canonical;
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
use crate::ty::fold::{TypeFolder, TypeVisitor};
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::ty::{self, AdtKind, List, Ty, TyCtxt};
|
||||
|
||||
|
@ -25,8 +23,6 @@ use std::rc::Rc;
|
|||
|
||||
pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
|
||||
|
||||
pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>;
|
||||
|
||||
pub use self::ObligationCauseCode::*;
|
||||
pub use self::SelectionError::*;
|
||||
pub use self::Vtable::*;
|
||||
|
@ -715,45 +711,6 @@ pub struct VtableTraitAliasData<'tcx, N> {
|
|||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
pub trait ExClauseFold<'tcx>
|
||||
where
|
||||
Self: chalk_engine::context::Context + Clone,
|
||||
{
|
||||
fn fold_ex_clause_with<F: TypeFolder<'tcx>>(
|
||||
ex_clause: &chalk_engine::ExClause<Self>,
|
||||
folder: &mut F,
|
||||
) -> chalk_engine::ExClause<Self>;
|
||||
|
||||
fn visit_ex_clause_with<V: TypeVisitor<'tcx>>(
|
||||
ex_clause: &chalk_engine::ExClause<Self>,
|
||||
visitor: &mut V,
|
||||
) -> bool;
|
||||
}
|
||||
|
||||
pub trait ChalkContextLift<'tcx>
|
||||
where
|
||||
Self: chalk_engine::context::Context + Clone,
|
||||
{
|
||||
type LiftedExClause: Debug + 'tcx;
|
||||
type LiftedDelayedLiteral: Debug + 'tcx;
|
||||
type LiftedLiteral: Debug + 'tcx;
|
||||
|
||||
fn lift_ex_clause_to_tcx(
|
||||
ex_clause: &chalk_engine::ExClause<Self>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<Self::LiftedExClause>;
|
||||
|
||||
fn lift_delayed_literal_to_tcx(
|
||||
ex_clause: &chalk_engine::DelayedLiteral<Self>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<Self::LiftedDelayedLiteral>;
|
||||
|
||||
fn lift_literal_to_tcx(
|
||||
ex_clause: &chalk_engine::Literal<Self>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<Self::LiftedLiteral>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum ObjectSafetyViolation {
|
||||
/// `Self: Sized` declared on the trait.
|
||||
|
|
|
@ -595,42 +595,6 @@ impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C>
|
||||
where
|
||||
C: chalk_engine::context::Context + Clone,
|
||||
C: traits::ChalkContextLift<'tcx>,
|
||||
{
|
||||
type Lifted = C::LiftedExClause;
|
||||
|
||||
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
<C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C>
|
||||
where
|
||||
C: chalk_engine::context::Context + Clone,
|
||||
C: traits::ChalkContextLift<'tcx>,
|
||||
{
|
||||
type Lifted = C::LiftedDelayedLiteral;
|
||||
|
||||
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
<C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C>
|
||||
where
|
||||
C: chalk_engine::context::Context + Clone,
|
||||
C: traits::ChalkContextLift<'tcx>,
|
||||
{
|
||||
type Lifted = C::LiftedLiteral;
|
||||
|
||||
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
<C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TypeFoldable implementations.
|
||||
|
||||
|
@ -674,39 +638,3 @@ impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> {
|
|||
self.iter().any(|t| t.visit_with(visitor))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C>
|
||||
where
|
||||
C: traits::ExClauseFold<'tcx>,
|
||||
C::Substitution: Clone,
|
||||
C::RegionConstraint: Clone,
|
||||
{
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
<C as traits::ExClauseFold>::fold_ex_clause_with(self, folder)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
<C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor)
|
||||
}
|
||||
}
|
||||
|
||||
EnumTypeFoldableImpl! {
|
||||
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> {
|
||||
(chalk_engine::DelayedLiteral::CannotProve)(a),
|
||||
(chalk_engine::DelayedLiteral::Negative)(a),
|
||||
(chalk_engine::DelayedLiteral::Positive)(a, b),
|
||||
} where
|
||||
C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone,
|
||||
}
|
||||
|
||||
EnumTypeFoldableImpl! {
|
||||
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> {
|
||||
(chalk_engine::Literal::Negative)(a),
|
||||
(chalk_engine::Literal::Positive)(a),
|
||||
} where
|
||||
C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone,
|
||||
}
|
||||
|
||||
CloneTypeFoldableAndLiftImpls! {
|
||||
chalk_engine::TableIndex,
|
||||
}
|
||||
|
|
|
@ -357,10 +357,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
|||
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
|
||||
// result.
|
||||
Err(mut ui) => {
|
||||
if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
self.canonicalize_ty_var(
|
||||
CanonicalVarInfo {
|
||||
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
|
||||
|
@ -447,10 +445,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
|||
// `ConstVar(vid)` is unresolved, track its universe index in the
|
||||
// canonicalized result
|
||||
Err(mut ui) => {
|
||||
if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
return self.canonicalize_const_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
|
||||
ct,
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
use crate::infer::canonical::OriginalQueryValues;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{
|
||||
Environment, FulfillmentError, FulfillmentErrorCode, InEnvironment, ObligationCause,
|
||||
PredicateObligation, SelectionError, TraitEngine,
|
||||
};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
pub use rustc::traits::ChalkCanonicalGoal as CanonicalGoal;
|
||||
|
||||
pub struct FulfillmentContext<'tcx> {
|
||||
obligations: FxHashSet<InEnvironment<'tcx, PredicateObligation<'tcx>>>,
|
||||
}
|
||||
|
||||
impl FulfillmentContext<'tcx> {
|
||||
crate fn new() -> Self {
|
||||
FulfillmentContext { obligations: FxHashSet::default() }
|
||||
}
|
||||
}
|
||||
|
||||
fn in_environment(
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) -> InEnvironment<'tcx, PredicateObligation<'tcx>> {
|
||||
assert!(!infcx.is_in_snapshot());
|
||||
let obligation = infcx.resolve_vars_if_possible(&obligation);
|
||||
|
||||
let environment = match obligation.param_env.def_id {
|
||||
Some(def_id) => infcx.tcx.environment(def_id),
|
||||
None if obligation.param_env.caller_bounds.is_empty() => {
|
||||
Environment { clauses: ty::List::empty() }
|
||||
}
|
||||
_ => bug!("non-empty `ParamEnv` with no def-id"),
|
||||
};
|
||||
|
||||
InEnvironment { environment, goal: obligation }
|
||||
}
|
||||
|
||||
impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||
fn normalize_projection_type(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
_param_env: ty::ParamEnv<'tcx>,
|
||||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
_cause: ObligationCause<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
infcx.tcx.mk_ty(ty::Projection(projection_ty))
|
||||
}
|
||||
|
||||
fn register_predicate_obligation(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) {
|
||||
self.obligations.insert(in_environment(infcx, obligation));
|
||||
}
|
||||
|
||||
fn select_all_or_error(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
|
||||
self.select_where_possible(infcx)?;
|
||||
|
||||
if self.obligations.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
let errors = self
|
||||
.obligations
|
||||
.iter()
|
||||
.map(|obligation| FulfillmentError {
|
||||
obligation: obligation.goal.clone(),
|
||||
code: FulfillmentErrorCode::CodeAmbiguity,
|
||||
points_at_arg_span: false,
|
||||
})
|
||||
.collect();
|
||||
Err(errors)
|
||||
}
|
||||
}
|
||||
|
||||
fn select_where_possible(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
|
||||
let mut errors = Vec::new();
|
||||
let mut next_round = FxHashSet::default();
|
||||
let mut making_progress;
|
||||
|
||||
loop {
|
||||
making_progress = false;
|
||||
|
||||
// We iterate over all obligations, and record if we are able
|
||||
// to unambiguously prove at least one obligation.
|
||||
for obligation in self.obligations.drain() {
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
let canonical_goal = infcx.canonicalize_query(
|
||||
&InEnvironment {
|
||||
environment: obligation.environment,
|
||||
goal: obligation.goal.predicate,
|
||||
},
|
||||
&mut orig_values,
|
||||
);
|
||||
|
||||
match infcx.tcx.evaluate_goal(canonical_goal) {
|
||||
Ok(response) => {
|
||||
if response.is_proven() {
|
||||
making_progress = true;
|
||||
|
||||
match infcx.instantiate_query_response_and_region_obligations(
|
||||
&obligation.goal.cause,
|
||||
obligation.goal.param_env,
|
||||
&orig_values,
|
||||
&response,
|
||||
) {
|
||||
Ok(infer_ok) => next_round.extend(
|
||||
infer_ok
|
||||
.obligations
|
||||
.into_iter()
|
||||
.map(|obligation| in_environment(infcx, obligation)),
|
||||
),
|
||||
|
||||
Err(_err) => errors.push(FulfillmentError {
|
||||
obligation: obligation.goal,
|
||||
code: FulfillmentErrorCode::CodeSelectionError(
|
||||
SelectionError::Unimplemented,
|
||||
),
|
||||
points_at_arg_span: false,
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
// Ambiguous: retry at next round.
|
||||
next_round.insert(obligation);
|
||||
}
|
||||
}
|
||||
|
||||
Err(NoSolution) => errors.push(FulfillmentError {
|
||||
obligation: obligation.goal,
|
||||
code: FulfillmentErrorCode::CodeSelectionError(
|
||||
SelectionError::Unimplemented,
|
||||
),
|
||||
points_at_arg_span: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
next_round = std::mem::replace(&mut self.obligations, next_round);
|
||||
|
||||
if !making_progress {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if errors.is_empty() { Ok(()) } else { Err(errors) }
|
||||
}
|
||||
|
||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||
self.obligations.iter().map(|obligation| obligation.goal.clone()).collect()
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ use crate::traits::Obligation;
|
|||
use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError};
|
||||
use super::{FulfillmentContext, FulfillmentError};
|
||||
use super::{ObligationCause, PredicateObligation};
|
||||
|
||||
pub trait TraitEngine<'tcx>: 'tcx {
|
||||
|
@ -78,11 +78,7 @@ impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
|||
}
|
||||
|
||||
impl dyn TraitEngine<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
|
||||
if tcx.sess.opts.debugging_opts.chalk {
|
||||
Box::new(ChalkFulfillmentContext::new())
|
||||
} else {
|
||||
Box::new(FulfillmentContext::new())
|
||||
}
|
||||
pub fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> {
|
||||
Box::new(FulfillmentContext::new())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -812,21 +812,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::Predicate::WellFormed(ty) => {
|
||||
if !self.tcx.sess.opts.debugging_opts.chalk {
|
||||
// WF predicates cannot themselves make
|
||||
// errors. They can only block due to
|
||||
// ambiguity; otherwise, they always
|
||||
// degenerate into other obligations
|
||||
// (which may fail).
|
||||
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
||||
} else {
|
||||
// FIXME: we'll need a better message which takes into account
|
||||
// which bounds actually failed to hold.
|
||||
self.tcx.sess.struct_span_err(
|
||||
span,
|
||||
&format!("the type `{}` is not well-formed (chalk)", ty),
|
||||
)
|
||||
}
|
||||
// WF predicates cannot themselves make
|
||||
// errors. They can only block due to
|
||||
// ambiguity; otherwise, they always
|
||||
// degenerate into other obligations
|
||||
// (which may fail).
|
||||
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#[allow(dead_code)]
|
||||
pub mod auto_trait;
|
||||
mod chalk_fulfill;
|
||||
pub mod codegen;
|
||||
mod coherence;
|
||||
mod engine;
|
||||
|
@ -74,10 +73,6 @@ pub use self::util::{
|
|||
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
|
||||
};
|
||||
|
||||
pub use self::chalk_fulfill::{
|
||||
CanonicalGoal as ChalkCanonicalGoal, FulfillmentContext as ChalkFulfillmentContext,
|
||||
};
|
||||
|
||||
pub use rustc::traits::*;
|
||||
|
||||
/// Whether to skip the leak check, as part of a future compatibility warning step.
|
||||
|
|
|
@ -2917,15 +2917,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
trait_ref,
|
||||
)?);
|
||||
|
||||
// FIXME: Chalk
|
||||
|
||||
if !self.tcx().sess.opts.debugging_opts.chalk {
|
||||
obligations.push(Obligation::new(
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
ty::Predicate::ClosureKind(closure_def_id, substs, kind),
|
||||
));
|
||||
}
|
||||
obligations.push(Obligation::new(
|
||||
obligation.cause.clone(),
|
||||
obligation.param_env,
|
||||
ty::Predicate::ClosureKind(closure_def_id, substs, kind),
|
||||
));
|
||||
|
||||
Ok(VtableClosureData { closure_def_id, substs: substs, nested: obligations })
|
||||
}
|
||||
|
|
|
@ -922,8 +922,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"tell the linker to strip debuginfo when building without debuginfo enabled."),
|
||||
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"make the current crate share its generic instantiations"),
|
||||
chalk: bool = (false, parse_bool, [TRACKED],
|
||||
"enable the experimental Chalk-based trait solving engine"),
|
||||
no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
|
||||
"don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
|
||||
no_leak_check: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
|
|
@ -17,6 +17,5 @@ rustc_macros = { path = "../librustc_macros" }
|
|||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_ast = { path = "../librustc_ast" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
chalk-engine = { version = "0.9.0", default-features=false }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
rustc_infer = { path = "../librustc_infer" }
|
||||
|
|
|
@ -1,638 +0,0 @@
|
|||
mod program_clauses;
|
||||
mod resolvent_ops;
|
||||
mod unify;
|
||||
|
||||
use chalk_engine::fallible::Fallible;
|
||||
use chalk_engine::forest::Forest;
|
||||
use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause, Literal};
|
||||
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::subst::{GenericArg, GenericArgKind};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_infer::infer::canonical::{
|
||||
Canonical, CanonicalVarValues, Certainty, OriginalQueryValues, QueryRegionConstraints,
|
||||
QueryResponse,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{
|
||||
self, ChalkCanonicalGoal, ChalkContextLift, Clause, DomainGoal, Environment, ExClauseFold,
|
||||
Goal, GoalKind, InEnvironment, QuantifierKind,
|
||||
};
|
||||
use rustc_macros::{Lift, TypeFoldable};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use std::fmt::{self, Debug};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use self::unify::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
crate struct ChalkArenas<'tcx> {
|
||||
_phantom: PhantomData<&'tcx ()>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
crate struct ChalkContext<'tcx> {
|
||||
_arenas: ChalkArenas<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
crate struct ChalkInferenceContext<'cx, 'tcx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
crate struct UniverseMap;
|
||||
|
||||
crate type RegionConstraint<'tcx> = ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, Lift)]
|
||||
crate struct ConstrainedSubst<'tcx> {
|
||||
subst: CanonicalVarValues<'tcx>,
|
||||
constraints: Vec<RegionConstraint<'tcx>>,
|
||||
}
|
||||
|
||||
impl context::Context for ChalkArenas<'tcx> {
|
||||
type CanonicalExClause = Canonical<'tcx, ChalkExClause<'tcx>>;
|
||||
|
||||
type CanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>;
|
||||
|
||||
// u-canonicalization not yet implemented
|
||||
type UCanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>;
|
||||
|
||||
type CanonicalConstrainedSubst = Canonical<'tcx, ConstrainedSubst<'tcx>>;
|
||||
|
||||
// u-canonicalization not yet implemented
|
||||
type UniverseMap = UniverseMap;
|
||||
|
||||
type Solution = Canonical<'tcx, QueryResponse<'tcx, ()>>;
|
||||
|
||||
type InferenceNormalizedSubst = CanonicalVarValues<'tcx>;
|
||||
|
||||
type GoalInEnvironment = InEnvironment<'tcx, Goal<'tcx>>;
|
||||
|
||||
type RegionConstraint = RegionConstraint<'tcx>;
|
||||
|
||||
type Substitution = CanonicalVarValues<'tcx>;
|
||||
|
||||
type Environment = Environment<'tcx>;
|
||||
|
||||
type Goal = Goal<'tcx>;
|
||||
|
||||
type DomainGoal = DomainGoal<'tcx>;
|
||||
|
||||
type BindersGoal = ty::Binder<Goal<'tcx>>;
|
||||
|
||||
type Parameter = GenericArg<'tcx>;
|
||||
|
||||
type ProgramClause = Clause<'tcx>;
|
||||
|
||||
type ProgramClauses = Vec<Clause<'tcx>>;
|
||||
|
||||
type UnificationResult = UnificationResult<'tcx>;
|
||||
|
||||
type Variance = ty::Variance;
|
||||
|
||||
fn goal_in_environment(
|
||||
env: &Environment<'tcx>,
|
||||
goal: Goal<'tcx>,
|
||||
) -> InEnvironment<'tcx, Goal<'tcx>> {
|
||||
env.with(goal)
|
||||
}
|
||||
}
|
||||
|
||||
impl context::AggregateOps<ChalkArenas<'tcx>> for ChalkContext<'tcx> {
|
||||
fn make_solution(
|
||||
&self,
|
||||
root_goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
mut simplified_answers: impl context::AnswerStream<ChalkArenas<'tcx>>,
|
||||
) -> Option<Canonical<'tcx, QueryResponse<'tcx, ()>>> {
|
||||
use chalk_engine::SimplifiedAnswer;
|
||||
|
||||
debug!("make_solution(root_goal = {:?})", root_goal);
|
||||
|
||||
if simplified_answers.peek_answer().is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let SimplifiedAnswer { subst: constrained_subst, ambiguous } =
|
||||
simplified_answers.next_answer().unwrap();
|
||||
|
||||
debug!("make_solution: ambiguous flag = {}", ambiguous);
|
||||
|
||||
let ambiguous = simplified_answers.peek_answer().is_some() || ambiguous;
|
||||
|
||||
let solution = constrained_subst.unchecked_map(|cs| match ambiguous {
|
||||
true => QueryResponse {
|
||||
var_values: cs.subst.make_identity(self.tcx),
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: Certainty::Ambiguous,
|
||||
value: (),
|
||||
},
|
||||
|
||||
false => QueryResponse {
|
||||
var_values: cs.subst,
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
|
||||
// FIXME: restore this later once we get better at handling regions
|
||||
// region_constraints: cs.constraints
|
||||
// .into_iter()
|
||||
// .map(|c| ty::Binder::bind(c))
|
||||
// .collect(),
|
||||
certainty: Certainty::Proven,
|
||||
value: (),
|
||||
},
|
||||
});
|
||||
|
||||
debug!("make_solution: solution = {:?}", solution);
|
||||
|
||||
Some(solution)
|
||||
}
|
||||
}
|
||||
|
||||
impl context::ContextOps<ChalkArenas<'tcx>> for ChalkContext<'tcx> {
|
||||
/// Returns `true` if this is a coinductive goal: basically proving that an auto trait
|
||||
/// is implemented or proving that a trait reference is well-formed.
|
||||
fn is_coinductive(&self, goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> bool {
|
||||
use rustc::traits::{WellFormed, WhereClause};
|
||||
|
||||
let mut goal = goal.value.goal;
|
||||
loop {
|
||||
match goal {
|
||||
GoalKind::DomainGoal(domain_goal) => match domain_goal {
|
||||
DomainGoal::WellFormed(WellFormed::Trait(..)) => return true,
|
||||
DomainGoal::Holds(WhereClause::Implemented(trait_predicate)) => {
|
||||
return self.tcx.trait_is_auto(trait_predicate.def_id());
|
||||
}
|
||||
_ => return false,
|
||||
},
|
||||
|
||||
GoalKind::Quantified(_, bound_goal) => goal = *bound_goal.skip_binder(),
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an inference table for processing a new goal and instantiate that goal
|
||||
/// in that context, returning "all the pieces".
|
||||
///
|
||||
/// More specifically: given a u-canonical goal `arg`, creates a
|
||||
/// new inference table `T` and populates it with the universes
|
||||
/// found in `arg`. Then, creates a substitution `S` that maps
|
||||
/// each bound variable in `arg` to a fresh inference variable
|
||||
/// from T. Returns:
|
||||
///
|
||||
/// - the table `T`,
|
||||
/// - the substitution `S`,
|
||||
/// - the environment and goal found by substitution `S` into `arg`.
|
||||
fn instantiate_ucanonical_goal<R>(
|
||||
&self,
|
||||
arg: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
op: impl context::WithInstantiatedUCanonicalGoal<ChalkArenas<'tcx>, Output = R>,
|
||||
) -> R {
|
||||
self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, arg, |ref infcx, arg, subst| {
|
||||
let chalk_infcx = &mut ChalkInferenceContext { infcx };
|
||||
op.with(chalk_infcx, subst, arg.environment, arg.goal)
|
||||
})
|
||||
}
|
||||
|
||||
fn instantiate_ex_clause<R>(
|
||||
&self,
|
||||
_num_universes: usize,
|
||||
arg: &Canonical<'tcx, ChalkExClause<'tcx>>,
|
||||
op: impl context::WithInstantiatedExClause<ChalkArenas<'tcx>, Output = R>,
|
||||
) -> R {
|
||||
self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &arg.upcast(), |ref infcx, arg, _| {
|
||||
let chalk_infcx = &mut ChalkInferenceContext { infcx };
|
||||
op.with(chalk_infcx, arg)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns `true` if this solution has no region constraints.
|
||||
fn empty_constraints(ccs: &Canonical<'tcx, ConstrainedSubst<'tcx>>) -> bool {
|
||||
ccs.value.constraints.is_empty()
|
||||
}
|
||||
|
||||
fn inference_normalized_subst_from_ex_clause(
|
||||
canon_ex_clause: &'a Canonical<'tcx, ChalkExClause<'tcx>>,
|
||||
) -> &'a CanonicalVarValues<'tcx> {
|
||||
&canon_ex_clause.value.subst
|
||||
}
|
||||
|
||||
fn inference_normalized_subst_from_subst(
|
||||
canon_subst: &'a Canonical<'tcx, ConstrainedSubst<'tcx>>,
|
||||
) -> &'a CanonicalVarValues<'tcx> {
|
||||
&canon_subst.value.subst
|
||||
}
|
||||
|
||||
fn canonical(
|
||||
u_canon: &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
) -> &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> {
|
||||
u_canon
|
||||
}
|
||||
|
||||
fn is_trivial_substitution(
|
||||
u_canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>,
|
||||
) -> bool {
|
||||
let subst = &canonical_subst.value.subst;
|
||||
assert_eq!(u_canon.variables.len(), subst.var_values.len());
|
||||
subst.var_values.iter_enumerated().all(|(cvar, kind)| match kind.unpack() {
|
||||
GenericArgKind::Lifetime(r) => match r {
|
||||
&ty::ReLateBound(debruijn, br) => {
|
||||
debug_assert_eq!(debruijn, ty::INNERMOST);
|
||||
cvar == br.assert_bound_var()
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
GenericArgKind::Type(ty) => match ty.kind {
|
||||
ty::Bound(debruijn, bound_ty) => {
|
||||
debug_assert_eq!(debruijn, ty::INNERMOST);
|
||||
cvar == bound_ty.var
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
GenericArgKind::Const(ct) => match ct.val {
|
||||
ty::ConstKind::Bound(debruijn, bound_ct) => {
|
||||
debug_assert_eq!(debruijn, ty::INNERMOST);
|
||||
cvar == bound_ct
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn num_universes(canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> usize {
|
||||
canon.max_universe.index() + 1
|
||||
}
|
||||
|
||||
/// Convert a goal G *from* the canonical universes *into* our
|
||||
/// local universes. This will yield a goal G' that is the same
|
||||
/// but for the universes of universally quantified names.
|
||||
fn map_goal_from_canonical(
|
||||
_map: &UniverseMap,
|
||||
value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> {
|
||||
*value // FIXME universe maps not implemented yet
|
||||
}
|
||||
|
||||
fn map_subst_from_canonical(
|
||||
_map: &UniverseMap,
|
||||
value: &Canonical<'tcx, ConstrainedSubst<'tcx>>,
|
||||
) -> Canonical<'tcx, ConstrainedSubst<'tcx>> {
|
||||
value.clone() // FIXME universe maps not implemented yet
|
||||
}
|
||||
}
|
||||
|
||||
impl context::InferenceTable<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
|
||||
for ChalkInferenceContext<'cx, 'tcx>
|
||||
{
|
||||
fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> {
|
||||
self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal))
|
||||
}
|
||||
|
||||
fn cannot_prove(&self) -> Goal<'tcx> {
|
||||
self.infcx.tcx.mk_goal(GoalKind::CannotProve)
|
||||
}
|
||||
|
||||
fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> {
|
||||
match *goal {
|
||||
GoalKind::Implies(hypotheses, goal) => {
|
||||
HhGoal::Implies(hypotheses.iter().cloned().collect(), goal)
|
||||
}
|
||||
GoalKind::And(left, right) => HhGoal::And(left, right),
|
||||
GoalKind::Not(subgoal) => HhGoal::Not(subgoal),
|
||||
GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d),
|
||||
GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder),
|
||||
GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder),
|
||||
GoalKind::Subtype(a, b) => HhGoal::Unify(ty::Variance::Covariant, a.into(), b.into()),
|
||||
GoalKind::CannotProve => HhGoal::CannotProve,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_clauses(
|
||||
&mut self,
|
||||
env: &Environment<'tcx>,
|
||||
clauses: Vec<Clause<'tcx>>,
|
||||
) -> Environment<'tcx> {
|
||||
Environment {
|
||||
clauses: self
|
||||
.infcx
|
||||
.tcx
|
||||
.mk_clauses(env.clauses.iter().cloned().chain(clauses.into_iter())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl context::TruncateOps<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
|
||||
for ChalkInferenceContext<'cx, 'tcx>
|
||||
{
|
||||
fn truncate_goal(
|
||||
&mut self,
|
||||
_subgoal: &InEnvironment<'tcx, Goal<'tcx>>,
|
||||
) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
|
||||
None // FIXME we should truncate at some point!
|
||||
}
|
||||
|
||||
fn truncate_answer(
|
||||
&mut self,
|
||||
_subst: &CanonicalVarValues<'tcx>,
|
||||
) -> Option<CanonicalVarValues<'tcx>> {
|
||||
None // FIXME we should truncate at some point!
|
||||
}
|
||||
}
|
||||
|
||||
impl context::UnificationOps<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
|
||||
for ChalkInferenceContext<'cx, 'tcx>
|
||||
{
|
||||
fn program_clauses(
|
||||
&self,
|
||||
environment: &Environment<'tcx>,
|
||||
goal: &DomainGoal<'tcx>,
|
||||
) -> Vec<Clause<'tcx>> {
|
||||
self.program_clauses_impl(environment, goal)
|
||||
}
|
||||
|
||||
fn instantiate_binders_universally(&mut self, arg: &ty::Binder<Goal<'tcx>>) -> Goal<'tcx> {
|
||||
self.infcx.replace_bound_vars_with_placeholders(arg).0
|
||||
}
|
||||
|
||||
fn instantiate_binders_existentially(&mut self, arg: &ty::Binder<Goal<'tcx>>) -> Goal<'tcx> {
|
||||
self.infcx
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
LateBoundRegionConversionTime::HigherRankedType,
|
||||
arg,
|
||||
)
|
||||
.0
|
||||
}
|
||||
|
||||
fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box<dyn Debug + 'v> {
|
||||
let string = format!("{:?}", self.infcx.resolve_vars_if_possible(value));
|
||||
Box::new(string)
|
||||
}
|
||||
|
||||
fn canonicalize_goal(
|
||||
&mut self,
|
||||
value: &InEnvironment<'tcx, Goal<'tcx>>,
|
||||
) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> {
|
||||
let mut _orig_values = OriginalQueryValues::default();
|
||||
self.infcx.canonicalize_query(value, &mut _orig_values)
|
||||
}
|
||||
|
||||
fn canonicalize_ex_clause(
|
||||
&mut self,
|
||||
value: &ChalkExClause<'tcx>,
|
||||
) -> Canonical<'tcx, ChalkExClause<'tcx>> {
|
||||
self.infcx.canonicalize_response(value)
|
||||
}
|
||||
|
||||
fn canonicalize_constrained_subst(
|
||||
&mut self,
|
||||
subst: CanonicalVarValues<'tcx>,
|
||||
constraints: Vec<RegionConstraint<'tcx>>,
|
||||
) -> Canonical<'tcx, ConstrainedSubst<'tcx>> {
|
||||
self.infcx.canonicalize_response(&ConstrainedSubst { subst, constraints })
|
||||
}
|
||||
|
||||
fn u_canonicalize_goal(
|
||||
&mut self,
|
||||
value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
) -> (Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, UniverseMap) {
|
||||
(*value, UniverseMap)
|
||||
}
|
||||
|
||||
fn invert_goal(
|
||||
&mut self,
|
||||
_value: &InEnvironment<'tcx, Goal<'tcx>>,
|
||||
) -> Option<InEnvironment<'tcx, Goal<'tcx>>> {
|
||||
panic!("goal inversion not yet implemented")
|
||||
}
|
||||
|
||||
fn unify_parameters(
|
||||
&mut self,
|
||||
environment: &Environment<'tcx>,
|
||||
variance: ty::Variance,
|
||||
a: &GenericArg<'tcx>,
|
||||
b: &GenericArg<'tcx>,
|
||||
) -> Fallible<UnificationResult<'tcx>> {
|
||||
self.infcx.commit_if_ok(|_| {
|
||||
unify(self.infcx, *environment, variance, a, b)
|
||||
.map_err(|_| chalk_engine::fallible::NoSolution)
|
||||
})
|
||||
}
|
||||
|
||||
fn sink_answer_subset(
|
||||
&self,
|
||||
value: &Canonical<'tcx, ConstrainedSubst<'tcx>>,
|
||||
) -> Canonical<'tcx, ConstrainedSubst<'tcx>> {
|
||||
value.clone()
|
||||
}
|
||||
|
||||
fn lift_delayed_literal(
|
||||
&self,
|
||||
value: DelayedLiteral<ChalkArenas<'tcx>>,
|
||||
) -> DelayedLiteral<ChalkArenas<'tcx>> {
|
||||
match self.infcx.tcx.lift(&value) {
|
||||
Some(literal) => literal,
|
||||
None => bug!("cannot lift {:?}", value),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_ex_clause(
|
||||
&mut self,
|
||||
result: UnificationResult<'tcx>,
|
||||
ex_clause: &mut ChalkExClause<'tcx>,
|
||||
) {
|
||||
into_ex_clause(result, ex_clause);
|
||||
}
|
||||
}
|
||||
|
||||
crate fn into_ex_clause(result: UnificationResult<'tcx>, ex_clause: &mut ChalkExClause<'tcx>) {
|
||||
ex_clause.subgoals.extend(result.goals.into_iter().map(Literal::Positive));
|
||||
|
||||
// FIXME: restore this later once we get better at handling regions
|
||||
let _ = result.constraints.len(); // trick `-D dead-code`
|
||||
// ex_clause.constraints.extend(result.constraints);
|
||||
}
|
||||
|
||||
type ChalkHhGoal<'tcx> = HhGoal<ChalkArenas<'tcx>>;
|
||||
|
||||
type ChalkExClause<'tcx> = ExClause<ChalkArenas<'tcx>>;
|
||||
|
||||
impl Debug for ChalkContext<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ChalkContext")
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for ChalkInferenceContext<'cx, 'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "ChalkInferenceContext")
|
||||
}
|
||||
}
|
||||
|
||||
impl ChalkContextLift<'tcx> for ChalkArenas<'a> {
|
||||
type LiftedExClause = ChalkExClause<'tcx>;
|
||||
type LiftedDelayedLiteral = DelayedLiteral<ChalkArenas<'tcx>>;
|
||||
type LiftedLiteral = Literal<ChalkArenas<'tcx>>;
|
||||
|
||||
fn lift_ex_clause_to_tcx(
|
||||
ex_clause: &ChalkExClause<'a>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<Self::LiftedExClause> {
|
||||
Some(ChalkExClause {
|
||||
subst: tcx.lift(&ex_clause.subst)?,
|
||||
delayed_literals: tcx.lift(&ex_clause.delayed_literals)?,
|
||||
constraints: tcx.lift(&ex_clause.constraints)?,
|
||||
subgoals: tcx.lift(&ex_clause.subgoals)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn lift_delayed_literal_to_tcx(
|
||||
literal: &DelayedLiteral<ChalkArenas<'a>>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<Self::LiftedDelayedLiteral> {
|
||||
Some(match literal {
|
||||
DelayedLiteral::CannotProve(()) => DelayedLiteral::CannotProve(()),
|
||||
DelayedLiteral::Negative(index) => DelayedLiteral::Negative(*index),
|
||||
DelayedLiteral::Positive(index, subst) => {
|
||||
DelayedLiteral::Positive(*index, tcx.lift(subst)?)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn lift_literal_to_tcx(
|
||||
literal: &Literal<ChalkArenas<'a>>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<Self::LiftedLiteral> {
|
||||
Some(match literal {
|
||||
Literal::Negative(goal) => Literal::Negative(tcx.lift(goal)?),
|
||||
Literal::Positive(goal) => Literal::Positive(tcx.lift(goal)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ExClauseFold<'tcx> for ChalkArenas<'tcx> {
|
||||
fn fold_ex_clause_with<F: TypeFolder<'tcx>>(
|
||||
ex_clause: &ChalkExClause<'tcx>,
|
||||
folder: &mut F,
|
||||
) -> ChalkExClause<'tcx> {
|
||||
ExClause {
|
||||
subst: ex_clause.subst.fold_with(folder),
|
||||
delayed_literals: ex_clause.delayed_literals.fold_with(folder),
|
||||
constraints: ex_clause.constraints.fold_with(folder),
|
||||
subgoals: ex_clause.subgoals.fold_with(folder),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ex_clause_with<V: TypeVisitor<'tcx>>(
|
||||
ex_clause: &ExClause<Self>,
|
||||
visitor: &mut V,
|
||||
) -> bool {
|
||||
let ExClause { subst, delayed_literals, constraints, subgoals } = ex_clause;
|
||||
subst.visit_with(visitor)
|
||||
|| delayed_literals.visit_with(visitor)
|
||||
|| constraints.visit_with(visitor)
|
||||
|| subgoals.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
trait Upcast<'tcx>: 'tcx {
|
||||
type Upcasted: 'tcx;
|
||||
|
||||
fn upcast(&self) -> Self::Upcasted;
|
||||
}
|
||||
|
||||
impl<'tcx> Upcast<'tcx> for DelayedLiteral<ChalkArenas<'tcx>> {
|
||||
type Upcasted = DelayedLiteral<ChalkArenas<'tcx>>;
|
||||
|
||||
fn upcast(&self) -> Self::Upcasted {
|
||||
match self {
|
||||
&DelayedLiteral::CannotProve(..) => DelayedLiteral::CannotProve(()),
|
||||
&DelayedLiteral::Negative(index) => DelayedLiteral::Negative(index),
|
||||
DelayedLiteral::Positive(index, subst) => {
|
||||
DelayedLiteral::Positive(*index, subst.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Upcast<'tcx> for Literal<ChalkArenas<'tcx>> {
|
||||
type Upcasted = Literal<ChalkArenas<'tcx>>;
|
||||
|
||||
fn upcast(&self) -> Self::Upcasted {
|
||||
match self {
|
||||
&Literal::Negative(goal) => Literal::Negative(goal),
|
||||
&Literal::Positive(goal) => Literal::Positive(goal),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Upcast<'tcx> for ExClause<ChalkArenas<'tcx>> {
|
||||
type Upcasted = ExClause<ChalkArenas<'tcx>>;
|
||||
|
||||
fn upcast(&self) -> Self::Upcasted {
|
||||
ExClause {
|
||||
subst: self.subst.clone(),
|
||||
delayed_literals: self.delayed_literals.iter().map(|l| l.upcast()).collect(),
|
||||
constraints: self.constraints.clone(),
|
||||
subgoals: self.subgoals.iter().map(|g| g.upcast()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> Upcast<'tcx> for Canonical<'tcx, T>
|
||||
where
|
||||
T: Upcast<'tcx>,
|
||||
{
|
||||
type Upcasted = Canonical<'tcx, T::Upcasted>;
|
||||
|
||||
fn upcast(&self) -> Self::Upcasted {
|
||||
Canonical {
|
||||
max_universe: self.max_universe,
|
||||
value: self.value.upcast(),
|
||||
variables: self.variables,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
*p = Providers { evaluate_goal, ..*p };
|
||||
}
|
||||
|
||||
crate fn evaluate_goal<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: ChalkCanonicalGoal<'tcx>,
|
||||
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> {
|
||||
use crate::lowering::Lower;
|
||||
use rustc::traits::WellFormed;
|
||||
|
||||
let goal = goal.unchecked_map(|goal| InEnvironment {
|
||||
environment: goal.environment,
|
||||
goal: match goal.goal {
|
||||
ty::Predicate::WellFormed(ty) => {
|
||||
tcx.mk_goal(GoalKind::DomainGoal(DomainGoal::WellFormed(WellFormed::Ty(ty))))
|
||||
}
|
||||
|
||||
ty::Predicate::Subtype(predicate) => tcx.mk_goal(GoalKind::Quantified(
|
||||
QuantifierKind::Universal,
|
||||
predicate.map_bound(|pred| tcx.mk_goal(GoalKind::Subtype(pred.a, pred.b))),
|
||||
)),
|
||||
|
||||
other => tcx.mk_goal(GoalKind::from_poly_domain_goal(other.lower(), tcx)),
|
||||
},
|
||||
});
|
||||
|
||||
debug!("evaluate_goal(goal = {:?})", goal);
|
||||
|
||||
let context = ChalkContext { _arenas: ChalkArenas { _phantom: PhantomData }, tcx };
|
||||
|
||||
let mut forest = Forest::new(context);
|
||||
let solution = forest.solve(&goal);
|
||||
|
||||
debug!("evaluate_goal: solution = {:?}", solution);
|
||||
|
||||
solution.map(|ok| Ok(&*tcx.arena.alloc(ok))).unwrap_or(Err(traits::query::NoSolution))
|
||||
}
|
|
@ -1,316 +0,0 @@
|
|||
use crate::generic_types;
|
||||
use crate::lowering::Lower;
|
||||
use rustc::traits::{Clause, GoalKind, ProgramClause, ProgramClauseCategory};
|
||||
use rustc::ty::subst::{GenericArg, InternalSubsts, Subst};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
/// Returns a predicate of the form
|
||||
/// `Implemented(ty: Trait) :- Implemented(nested: Trait)...`
|
||||
/// where `Trait` is specified by `trait_def_id`.
|
||||
fn builtin_impl_clause(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
nested: &[GenericArg<'tcx>],
|
||||
trait_def_id: DefId,
|
||||
) -> ProgramClause<'tcx> {
|
||||
ProgramClause {
|
||||
goal: ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) },
|
||||
}
|
||||
.lower(),
|
||||
hypotheses: tcx.mk_goals(
|
||||
nested
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|nested_ty| ty::TraitRef {
|
||||
def_id: trait_def_id,
|
||||
substs: tcx.mk_substs_trait(nested_ty.expect_ty(), &[]),
|
||||
})
|
||||
.map(|trait_ref| ty::TraitPredicate { trait_ref })
|
||||
.map(|pred| GoalKind::DomainGoal(pred.lower()))
|
||||
.map(|goal_kind| tcx.mk_goal(goal_kind)),
|
||||
),
|
||||
category: ProgramClauseCategory::Other,
|
||||
}
|
||||
}
|
||||
|
||||
crate fn assemble_builtin_unsize_impls<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
unsize_def_id: DefId,
|
||||
source: Ty<'tcx>,
|
||||
target: Ty<'tcx>,
|
||||
clauses: &mut Vec<Clause<'tcx>>,
|
||||
) {
|
||||
match (&source.kind, &target.kind) {
|
||||
(ty::Dynamic(data_a, ..), ty::Dynamic(data_b, ..)) => {
|
||||
if data_a.principal_def_id() != data_b.principal_def_id()
|
||||
|| data_b.auto_traits().any(|b| data_a.auto_traits().all(|a| a != b))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: rules for trait upcast
|
||||
}
|
||||
|
||||
(_, &ty::Dynamic(..)) => {
|
||||
// FIXME: basically, we should have something like:
|
||||
// ```
|
||||
// forall<T> {
|
||||
// Implemented(T: Unsize< for<...> dyn Trait<...> >) :-
|
||||
// for<...> Implemented(T: Trait<...>).
|
||||
// }
|
||||
// ```
|
||||
// The question is: how to correctly handle the higher-ranked
|
||||
// `for<...>` binder in order to have a generic rule?
|
||||
// (Having generic rules is useful for caching, as we may be able
|
||||
// to turn this function and others into tcx queries later on).
|
||||
}
|
||||
|
||||
(ty::Array(_, length), ty::Slice(_)) => {
|
||||
let ty_param = generic_types::bound(tcx, 0);
|
||||
let array_ty = tcx.mk_ty(ty::Array(ty_param, length));
|
||||
let slice_ty = tcx.mk_ty(ty::Slice(ty_param));
|
||||
|
||||
// `forall<T> { Implemented([T; N]: Unsize<[T]>). }`
|
||||
let clause = ProgramClause {
|
||||
goal: ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef {
|
||||
def_id: unsize_def_id,
|
||||
substs: tcx.mk_substs_trait(array_ty, &[slice_ty.into()]),
|
||||
},
|
||||
}
|
||||
.lower(),
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::Other,
|
||||
};
|
||||
|
||||
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
|
||||
}
|
||||
|
||||
(ty::Infer(ty::TyVar(_)), _) | (_, ty::Infer(ty::TyVar(_))) => {
|
||||
// FIXME: ambiguous
|
||||
}
|
||||
|
||||
(ty::Adt(def_id_a, ..), ty::Adt(def_id_b, ..)) => {
|
||||
if def_id_a != def_id_b {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: rules for struct unsizing
|
||||
}
|
||||
|
||||
(&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
|
||||
if tys_a.len() != tys_b.len() {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: rules for tuple unsizing
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn assemble_builtin_sized_impls<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sized_def_id: DefId,
|
||||
ty: Ty<'tcx>,
|
||||
clauses: &mut Vec<Clause<'tcx>>,
|
||||
) {
|
||||
let mut push_builtin_impl = |ty: Ty<'tcx>, nested: &[GenericArg<'tcx>]| {
|
||||
let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id);
|
||||
// Bind innermost bound vars that may exist in `ty` and `nested`.
|
||||
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
|
||||
};
|
||||
|
||||
match &ty.kind {
|
||||
// Non parametric primitive types.
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
| ty::Infer(ty::IntVar(_))
|
||||
| ty::Infer(ty::FloatVar(_))
|
||||
| ty::Error
|
||||
| ty::Never => push_builtin_impl(ty, &[]),
|
||||
|
||||
// These ones are always `Sized`.
|
||||
&ty::Array(_, length) => {
|
||||
push_builtin_impl(tcx.mk_ty(ty::Array(generic_types::bound(tcx, 0), length)), &[]);
|
||||
}
|
||||
ty::RawPtr(ptr) => {
|
||||
push_builtin_impl(generic_types::raw_ptr(tcx, ptr.mutbl), &[]);
|
||||
}
|
||||
&ty::Ref(_, _, mutbl) => {
|
||||
push_builtin_impl(generic_types::ref_ty(tcx, mutbl), &[]);
|
||||
}
|
||||
ty::FnPtr(fn_ptr) => {
|
||||
let fn_ptr = fn_ptr.skip_binder();
|
||||
let fn_ptr = generic_types::fn_ptr(
|
||||
tcx,
|
||||
fn_ptr.inputs_and_output.len(),
|
||||
fn_ptr.c_variadic,
|
||||
fn_ptr.unsafety,
|
||||
fn_ptr.abi,
|
||||
);
|
||||
push_builtin_impl(fn_ptr, &[]);
|
||||
}
|
||||
&ty::FnDef(def_id, ..) => {
|
||||
push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
|
||||
}
|
||||
&ty::Closure(def_id, ..) => {
|
||||
push_builtin_impl(generic_types::closure(tcx, def_id), &[]);
|
||||
}
|
||||
&ty::Generator(def_id, ..) => {
|
||||
push_builtin_impl(generic_types::generator(tcx, def_id), &[]);
|
||||
}
|
||||
|
||||
// `Sized` if the last type is `Sized` (because else we will get a WF error anyway).
|
||||
&ty::Tuple(type_list) => {
|
||||
let type_list = generic_types::type_list(tcx, type_list.len());
|
||||
push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &type_list);
|
||||
}
|
||||
|
||||
// Struct def
|
||||
ty::Adt(adt_def, _) => {
|
||||
let substs = InternalSubsts::bound_vars_for_item(tcx, adt_def.did);
|
||||
let adt = tcx.mk_ty(ty::Adt(adt_def, substs));
|
||||
let sized_constraint = adt_def
|
||||
.sized_constraint(tcx)
|
||||
.iter()
|
||||
.map(|ty| GenericArg::from(ty.subst(tcx, substs)))
|
||||
.collect::<Vec<_>>();
|
||||
push_builtin_impl(adt, &sized_constraint);
|
||||
}
|
||||
|
||||
// Artificially trigger an ambiguity by adding two possible types to
|
||||
// unify against.
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
push_builtin_impl(tcx.types.i32, &[]);
|
||||
push_builtin_impl(tcx.types.f32, &[]);
|
||||
}
|
||||
|
||||
ty::Projection(_projection_ty) => {
|
||||
// FIXME: add builtin impls from the associated type values found in
|
||||
// trait impls of `projection_ty.trait_ref(tcx)`.
|
||||
}
|
||||
|
||||
// The `Sized` bound can only come from the environment.
|
||||
ty::Param(..) | ty::Placeholder(..) | ty::UnnormalizedProjection(..) => (),
|
||||
|
||||
// Definitely not `Sized`.
|
||||
ty::Foreign(..) | ty::Str | ty::Slice(..) | ty::Dynamic(..) | ty::Opaque(..) => (),
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Infer(ty::FreshTy(_))
|
||||
| ty::Infer(ty::FreshIntTy(_))
|
||||
| ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn assemble_builtin_copy_clone_impls<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
ty: Ty<'tcx>,
|
||||
clauses: &mut Vec<Clause<'tcx>>,
|
||||
) {
|
||||
let mut push_builtin_impl = |ty: Ty<'tcx>, nested: &[GenericArg<'tcx>]| {
|
||||
let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id);
|
||||
// Bind innermost bound vars that may exist in `ty` and `nested`.
|
||||
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
|
||||
};
|
||||
|
||||
match &ty.kind {
|
||||
// Implementations provided in libcore.
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
| ty::RawPtr(..)
|
||||
| ty::Never
|
||||
| ty::Ref(_, _, hir::Mutability::Not) => (),
|
||||
|
||||
// Non parametric primitive types.
|
||||
ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::Error => {
|
||||
push_builtin_impl(ty, &[])
|
||||
}
|
||||
|
||||
// These implement `Copy`/`Clone` if their element types do.
|
||||
&ty::Array(_, length) => {
|
||||
let element_ty = generic_types::bound(tcx, 0);
|
||||
push_builtin_impl(
|
||||
tcx.mk_ty(ty::Array(element_ty, length)),
|
||||
&[GenericArg::from(element_ty)],
|
||||
);
|
||||
}
|
||||
&ty::Tuple(type_list) => {
|
||||
let type_list = generic_types::type_list(tcx, type_list.len());
|
||||
push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list);
|
||||
}
|
||||
&ty::Closure(def_id, ..) => {
|
||||
let closure_ty = generic_types::closure(tcx, def_id);
|
||||
let upvar_tys: Vec<_> = match &closure_ty.kind {
|
||||
ty::Closure(_, substs) => substs
|
||||
.as_closure()
|
||||
.upvar_tys(def_id, tcx)
|
||||
.map(|ty| GenericArg::from(ty))
|
||||
.collect(),
|
||||
_ => bug!(),
|
||||
};
|
||||
push_builtin_impl(closure_ty, &upvar_tys);
|
||||
}
|
||||
|
||||
// These ones are always `Clone`.
|
||||
ty::FnPtr(fn_ptr) => {
|
||||
let fn_ptr = fn_ptr.skip_binder();
|
||||
let fn_ptr = generic_types::fn_ptr(
|
||||
tcx,
|
||||
fn_ptr.inputs_and_output.len(),
|
||||
fn_ptr.c_variadic,
|
||||
fn_ptr.unsafety,
|
||||
fn_ptr.abi,
|
||||
);
|
||||
push_builtin_impl(fn_ptr, &[]);
|
||||
}
|
||||
&ty::FnDef(def_id, ..) => {
|
||||
push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
|
||||
}
|
||||
|
||||
// These depend on whatever user-defined impls might exist.
|
||||
ty::Adt(_, _) => (),
|
||||
|
||||
// Artificially trigger an ambiguity by adding two possible types to
|
||||
// unify against.
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
push_builtin_impl(tcx.types.i32, &[]);
|
||||
push_builtin_impl(tcx.types.f32, &[]);
|
||||
}
|
||||
|
||||
ty::Projection(_projection_ty) => {
|
||||
// FIXME: add builtin impls from the associated type values found in
|
||||
// trait impls of `projection_ty.trait_ref(tcx)`.
|
||||
}
|
||||
|
||||
// The `Copy`/`Clone` bound can only come from the environment.
|
||||
ty::Param(..) | ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Opaque(..) => (),
|
||||
|
||||
// Definitely not `Copy`/`Clone`.
|
||||
ty::Dynamic(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Generator(..)
|
||||
| ty::Str
|
||||
| ty::Slice(..)
|
||||
| ty::Ref(_, _, hir::Mutability::Mut) => (),
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Infer(ty::FreshTy(_))
|
||||
| ty::Infer(ty::FreshIntTy(_))
|
||||
| ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty),
|
||||
}
|
||||
}
|
|
@ -1,300 +0,0 @@
|
|||
mod builtin;
|
||||
mod primitive;
|
||||
|
||||
use super::ChalkInferenceContext;
|
||||
use rustc::traits::{
|
||||
Clause, DomainGoal, Environment, FromEnv, ProgramClause, ProgramClauseCategory, WellFormed,
|
||||
};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use std::iter;
|
||||
|
||||
use self::builtin::*;
|
||||
use self::primitive::*;
|
||||
|
||||
fn assemble_clauses_from_impls<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
clauses: &mut Vec<Clause<'tcx>>,
|
||||
) {
|
||||
tcx.for_each_impl(trait_def_id, |impl_def_id| {
|
||||
clauses.extend(tcx.program_clauses_for(impl_def_id).into_iter().cloned());
|
||||
});
|
||||
}
|
||||
|
||||
fn assemble_clauses_from_assoc_ty_values<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
clauses: &mut Vec<Clause<'tcx>>,
|
||||
) {
|
||||
tcx.for_each_impl(trait_def_id, |impl_def_id| {
|
||||
for def_id in tcx.associated_item_def_ids(impl_def_id).iter() {
|
||||
clauses.extend(tcx.program_clauses_for(*def_id).into_iter().cloned());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
impl ChalkInferenceContext<'cx, 'tcx> {
|
||||
pub(super) fn program_clauses_impl(
|
||||
&self,
|
||||
environment: &Environment<'tcx>,
|
||||
goal: &DomainGoal<'tcx>,
|
||||
) -> Vec<Clause<'tcx>> {
|
||||
use rustc::infer::canonical::OriginalQueryValues;
|
||||
use rustc::traits::WhereClause::*;
|
||||
|
||||
let goal = self.infcx.resolve_vars_if_possible(goal);
|
||||
|
||||
debug!("program_clauses(goal = {:?})", goal);
|
||||
|
||||
let mut clauses = match goal {
|
||||
DomainGoal::Holds(Implemented(trait_predicate)) => {
|
||||
// These come from:
|
||||
// * implementations of the trait itself (rule `Implemented-From-Impl`)
|
||||
// * the trait decl (rule `Implemented-From-Env`)
|
||||
|
||||
let mut clauses = vec![];
|
||||
|
||||
assemble_clauses_from_impls(self.infcx.tcx, trait_predicate.def_id(), &mut clauses);
|
||||
|
||||
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().sized_trait() {
|
||||
assemble_builtin_sized_impls(
|
||||
self.infcx.tcx,
|
||||
trait_predicate.def_id(),
|
||||
trait_predicate.self_ty(),
|
||||
&mut clauses,
|
||||
);
|
||||
}
|
||||
|
||||
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().unsize_trait() {
|
||||
let source = trait_predicate.self_ty();
|
||||
let target = trait_predicate.trait_ref.substs.type_at(1);
|
||||
assemble_builtin_unsize_impls(
|
||||
self.infcx.tcx,
|
||||
trait_predicate.def_id(),
|
||||
source,
|
||||
target,
|
||||
&mut clauses,
|
||||
);
|
||||
}
|
||||
|
||||
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().copy_trait() {
|
||||
assemble_builtin_copy_clone_impls(
|
||||
self.infcx.tcx,
|
||||
trait_predicate.def_id(),
|
||||
trait_predicate.self_ty(),
|
||||
&mut clauses,
|
||||
);
|
||||
}
|
||||
|
||||
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().clone_trait() {
|
||||
// For all builtin impls, the conditions for `Copy` and
|
||||
// `Clone` are the same.
|
||||
assemble_builtin_copy_clone_impls(
|
||||
self.infcx.tcx,
|
||||
trait_predicate.def_id(),
|
||||
trait_predicate.self_ty(),
|
||||
&mut clauses,
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: we need to add special rules for other builtin impls:
|
||||
// * `Generator`
|
||||
// * `FnOnce` / `FnMut` / `Fn`
|
||||
// * trait objects
|
||||
// * auto traits
|
||||
|
||||
// Rule `Implemented-From-Env` will be computed from the environment.
|
||||
clauses
|
||||
}
|
||||
|
||||
DomainGoal::Holds(ProjectionEq(projection_predicate)) => {
|
||||
// These come from:
|
||||
// * the assoc type definition (rule `ProjectionEq-Placeholder`)
|
||||
// * normalization of the assoc ty values (rule `ProjectionEq-Normalize`)
|
||||
// * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
|
||||
// * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
|
||||
|
||||
let clauses = self
|
||||
.infcx
|
||||
.tcx
|
||||
.program_clauses_for(projection_predicate.projection_ty.item_def_id)
|
||||
.into_iter()
|
||||
// only select `ProjectionEq-Placeholder` and `ProjectionEq-Normalize`
|
||||
.filter(|clause| clause.category() == ProgramClauseCategory::Other)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Rules `Implied-Bound-From-Trait` and `Implied-Bound-From-Type` will be computed
|
||||
// from the environment.
|
||||
clauses
|
||||
}
|
||||
|
||||
// For outlive requirements, just assume they hold. `ResolventOps::resolvent_clause`
|
||||
// will register them as actual region constraints later.
|
||||
DomainGoal::Holds(RegionOutlives(..)) | DomainGoal::Holds(TypeOutlives(..)) => {
|
||||
vec![Clause::Implies(ProgramClause {
|
||||
goal,
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::Other,
|
||||
})]
|
||||
}
|
||||
|
||||
DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => {
|
||||
// These come from -- the trait decl (rule `WellFormed-TraitRef`).
|
||||
self.infcx
|
||||
.tcx
|
||||
.program_clauses_for(trait_predicate.def_id())
|
||||
.into_iter()
|
||||
// only select `WellFormed-TraitRef`
|
||||
.filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
DomainGoal::WellFormed(WellFormed::Ty(ty)) => {
|
||||
// These come from:
|
||||
// * the associated type definition if `ty` refers to an unnormalized
|
||||
// associated type (rule `WellFormed-AssocTy`)
|
||||
// * custom rules for built-in types
|
||||
// * the type definition otherwise (rule `WellFormed-Type`)
|
||||
let clauses = match ty.kind {
|
||||
ty::Projection(data) => self.infcx.tcx.program_clauses_for(data.item_def_id),
|
||||
|
||||
// These types are always WF.
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
| ty::Str
|
||||
| ty::Param(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Error
|
||||
| ty::Never => {
|
||||
let wf_clause = ProgramClause {
|
||||
goal,
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::Implies(wf_clause);
|
||||
|
||||
self.infcx.tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
||||
|
||||
// Always WF (recall that we do not check for parameters to be WF).
|
||||
ty::RawPtr(ptr) => wf_clause_for_raw_ptr(self.infcx.tcx, ptr.mutbl),
|
||||
|
||||
// Always WF (recall that we do not check for parameters to be WF).
|
||||
ty::FnPtr(fn_ptr) => {
|
||||
let fn_ptr = fn_ptr.skip_binder();
|
||||
wf_clause_for_fn_ptr(
|
||||
self.infcx.tcx,
|
||||
fn_ptr.inputs_and_output.len(),
|
||||
fn_ptr.c_variadic,
|
||||
fn_ptr.unsafety,
|
||||
fn_ptr.abi,
|
||||
)
|
||||
}
|
||||
|
||||
// WF if inner type is `Sized`.
|
||||
ty::Slice(..) => wf_clause_for_slice(self.infcx.tcx),
|
||||
|
||||
// WF if inner type is `Sized`.
|
||||
ty::Array(_, length) => wf_clause_for_array(self.infcx.tcx, length),
|
||||
|
||||
// WF if all types but the last one are `Sized`.
|
||||
ty::Tuple(types) => wf_clause_for_tuple(self.infcx.tcx, types.len()),
|
||||
|
||||
// WF if `sub_ty` outlives `region`.
|
||||
ty::Ref(_, _, mutbl) => wf_clause_for_ref(self.infcx.tcx, mutbl),
|
||||
|
||||
ty::FnDef(def_id, ..) => wf_clause_for_fn_def(self.infcx.tcx, def_id),
|
||||
|
||||
ty::Dynamic(..) => {
|
||||
// FIXME: no rules yet for trait objects
|
||||
ty::List::empty()
|
||||
}
|
||||
|
||||
ty::Adt(def, ..) => self.infcx.tcx.program_clauses_for(def.did),
|
||||
|
||||
// FIXME: these are probably wrong
|
||||
ty::Foreign(def_id)
|
||||
| ty::Closure(def_id, ..)
|
||||
| ty::Generator(def_id, ..)
|
||||
| ty::Opaque(def_id, ..) => self.infcx.tcx.program_clauses_for(def_id),
|
||||
|
||||
// Artificially trigger an ambiguity.
|
||||
ty::Infer(..) => {
|
||||
let tcx = self.infcx.tcx;
|
||||
let types = [tcx.types.i32, tcx.types.u32, tcx.types.f32, tcx.types.f64];
|
||||
let clauses = types
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|ty| ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
})
|
||||
.map(|clause| Clause::Implies(clause));
|
||||
tcx.mk_clauses(clauses)
|
||||
}
|
||||
|
||||
ty::GeneratorWitness(..) | ty::UnnormalizedProjection(..) | ty::Bound(..) => {
|
||||
bug!("unexpected type {:?}", ty)
|
||||
}
|
||||
};
|
||||
|
||||
clauses
|
||||
.into_iter()
|
||||
.filter(|clause| clause.category() == ProgramClauseCategory::WellFormed)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
DomainGoal::FromEnv(FromEnv::Trait(..)) => {
|
||||
// These come from:
|
||||
// * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`)
|
||||
// * implied bounds from type definitions (rule `Implied-Bound-From-Type`)
|
||||
// * implied bounds from assoc type defs (rules `Implied-Trait-From-AssocTy`,
|
||||
// `Implied-Bound-From-AssocTy` and `Implied-WC-From-AssocTy`)
|
||||
|
||||
// All of these rules are computed in the environment.
|
||||
vec![]
|
||||
}
|
||||
|
||||
DomainGoal::FromEnv(FromEnv::Ty(..)) => {
|
||||
// There are no `FromEnv::Ty(..) :- ...` rules (this predicate only
|
||||
// comes from the environment).
|
||||
vec![]
|
||||
}
|
||||
|
||||
DomainGoal::Normalize(projection_predicate) => {
|
||||
// These come from -- assoc ty values (rule `Normalize-From-Impl`).
|
||||
let mut clauses = vec![];
|
||||
|
||||
assemble_clauses_from_assoc_ty_values(
|
||||
self.infcx.tcx,
|
||||
projection_predicate.projection_ty.trait_ref(self.infcx.tcx).def_id,
|
||||
&mut clauses,
|
||||
);
|
||||
|
||||
clauses
|
||||
}
|
||||
};
|
||||
|
||||
debug!("program_clauses: clauses = {:?}", clauses);
|
||||
debug!("program_clauses: adding clauses from environment = {:?}", environment);
|
||||
|
||||
let mut _orig_query_values = OriginalQueryValues::default();
|
||||
let canonical_environment =
|
||||
self.infcx.canonicalize_query(environment, &mut _orig_query_values).value;
|
||||
let env_clauses = self.infcx.tcx.program_clauses_for_env(canonical_environment);
|
||||
|
||||
debug!("program_clauses: env_clauses = {:?}", env_clauses);
|
||||
|
||||
clauses.extend(env_clauses.into_iter().cloned());
|
||||
clauses.extend(environment.clauses.iter().cloned());
|
||||
clauses
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
use crate::generic_types;
|
||||
use crate::lowering::Lower;
|
||||
use rustc::traits::{
|
||||
Clause, Clauses, DomainGoal, GoalKind, ProgramClause, ProgramClauseCategory, WellFormed,
|
||||
};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_target::spec::abi;
|
||||
use std::iter;
|
||||
|
||||
crate fn wf_clause_for_raw_ptr(tcx: TyCtxt<'_>, mutbl: hir::Mutability) -> Clauses<'_> {
|
||||
let ptr_ty = generic_types::raw_ptr(tcx, mutbl);
|
||||
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)),
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::Implies(wf_clause);
|
||||
|
||||
// `forall<T> { WellFormed(*const T). }`
|
||||
tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
||||
|
||||
crate fn wf_clause_for_fn_ptr(
|
||||
tcx: TyCtxt<'_>,
|
||||
arity_and_output: usize,
|
||||
variadic: bool,
|
||||
unsafety: hir::Unsafety,
|
||||
abi: abi::Abi,
|
||||
) -> Clauses<'_> {
|
||||
let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, variadic, unsafety, abi);
|
||||
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)),
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
// `forall <T1, ..., Tn+1> { WellFormed(for<> fn(T1, ..., Tn) -> Tn+1). }`
|
||||
// where `n + 1` == `arity_and_output`
|
||||
tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
||||
|
||||
crate fn wf_clause_for_slice(tcx: TyCtxt<'_>) -> Clauses<'_> {
|
||||
let ty = generic_types::bound(tcx, 0);
|
||||
let slice_ty = tcx.mk_slice(ty);
|
||||
|
||||
let sized_trait = match tcx.lang_items().sized_trait() {
|
||||
Some(def_id) => def_id,
|
||||
None => return ty::List::empty(),
|
||||
};
|
||||
let sized_implemented =
|
||||
ty::TraitRef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, ty::List::empty()) };
|
||||
let sized_implemented: DomainGoal<'_> =
|
||||
ty::TraitPredicate { trait_ref: sized_implemented }.lower();
|
||||
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(slice_ty)),
|
||||
hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
// `forall<T> { WellFormed([T]) :- Implemented(T: Sized). }`
|
||||
tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
||||
|
||||
crate fn wf_clause_for_array<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
length: &'tcx ty::Const<'tcx>,
|
||||
) -> Clauses<'tcx> {
|
||||
let ty = generic_types::bound(tcx, 0);
|
||||
let array_ty = tcx.mk_ty(ty::Array(ty, length));
|
||||
|
||||
let sized_trait = match tcx.lang_items().sized_trait() {
|
||||
Some(def_id) => def_id,
|
||||
None => return ty::List::empty(),
|
||||
};
|
||||
let sized_implemented =
|
||||
ty::TraitRef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, ty::List::empty()) };
|
||||
let sized_implemented: DomainGoal<'_> =
|
||||
ty::TraitPredicate { trait_ref: sized_implemented }.lower();
|
||||
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(array_ty)),
|
||||
hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
// `forall<T> { WellFormed([T; length]) :- Implemented(T: Sized). }`
|
||||
tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
||||
|
||||
crate fn wf_clause_for_tuple(tcx: TyCtxt<'_>, arity: usize) -> Clauses<'_> {
|
||||
let type_list = generic_types::type_list(tcx, arity);
|
||||
let tuple_ty = tcx.mk_ty(ty::Tuple(type_list));
|
||||
|
||||
let sized_trait = match tcx.lang_items().sized_trait() {
|
||||
Some(def_id) => def_id,
|
||||
None => return ty::List::empty(),
|
||||
};
|
||||
|
||||
// If `arity == 0` (i.e. the unit type) or `arity == 1`, this list of
|
||||
// hypotheses is actually empty.
|
||||
let sized_implemented = type_list[0..std::cmp::max(arity, 1) - 1]
|
||||
.iter()
|
||||
.map(|ty| ty::TraitRef {
|
||||
def_id: sized_trait,
|
||||
substs: tcx.mk_substs_trait(ty.expect_ty(), ty::List::empty()),
|
||||
})
|
||||
.map(|trait_ref| ty::TraitPredicate { trait_ref })
|
||||
.map(|predicate| predicate.lower());
|
||||
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(tuple_ty)),
|
||||
hypotheses: tcx.mk_goals(
|
||||
sized_implemented.map(|domain_goal| tcx.mk_goal(GoalKind::DomainGoal(domain_goal))),
|
||||
),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
// ```
|
||||
// forall<T1, ..., Tn-1, Tn> {
|
||||
// WellFormed((T1, ..., Tn)) :-
|
||||
// Implemented(T1: Sized),
|
||||
// ...
|
||||
// Implemented(Tn-1: Sized).
|
||||
// }
|
||||
// ```
|
||||
tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
||||
|
||||
crate fn wf_clause_for_ref(tcx: TyCtxt<'_>, mutbl: hir::Mutability) -> Clauses<'_> {
|
||||
let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)));
|
||||
let ty = generic_types::bound(tcx, 1);
|
||||
let ref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty, mutbl });
|
||||
|
||||
let outlives: DomainGoal<'_> = ty::OutlivesPredicate(ty, region).lower();
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)),
|
||||
hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(outlives.into_goal()))),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
// `forall<'a, T> { WellFormed(&'a T) :- Outlives(T: 'a). }`
|
||||
tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
||||
|
||||
crate fn wf_clause_for_fn_def(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
|
||||
let fn_def = generic_types::fn_def(tcx, def_id);
|
||||
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(fn_def)),
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
// `forall <T1, ..., Tn+1> { WellFormed(fn some_fn(T1, ..., Tn) -> Tn+1). }`
|
||||
// where `def_id` maps to the `some_fn` function definition
|
||||
tcx.mk_clauses(iter::once(wf_clause))
|
||||
}
|
|
@ -1,297 +0,0 @@
|
|||
use chalk_engine::fallible::{Fallible, NoSolution};
|
||||
use chalk_engine::{context, ExClause, Literal};
|
||||
use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc::ty::subst::GenericArg;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime};
|
||||
use rustc_infer::traits::{
|
||||
Clause, DomainGoal, Environment, Goal, GoalKind, InEnvironment, ProgramClause, WhereClause,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use super::unify::*;
|
||||
use super::{ChalkArenas, ChalkExClause, ChalkInferenceContext, ConstrainedSubst};
|
||||
|
||||
impl context::ResolventOps<ChalkArenas<'tcx>, ChalkArenas<'tcx>>
|
||||
for ChalkInferenceContext<'cx, 'tcx>
|
||||
{
|
||||
fn resolvent_clause(
|
||||
&mut self,
|
||||
environment: &Environment<'tcx>,
|
||||
goal: &DomainGoal<'tcx>,
|
||||
subst: &CanonicalVarValues<'tcx>,
|
||||
clause: &Clause<'tcx>,
|
||||
) -> Fallible<Canonical<'tcx, ChalkExClause<'tcx>>> {
|
||||
use chalk_engine::context::UnificationOps;
|
||||
|
||||
debug!("resolvent_clause(goal = {:?}, clause = {:?})", goal, clause);
|
||||
|
||||
let result = self.infcx.probe(|_| {
|
||||
let ProgramClause { goal: consequence, hypotheses, .. } = match clause {
|
||||
Clause::Implies(program_clause) => *program_clause,
|
||||
Clause::ForAll(program_clause) => {
|
||||
self.infcx
|
||||
.replace_bound_vars_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
LateBoundRegionConversionTime::HigherRankedType,
|
||||
program_clause,
|
||||
)
|
||||
.0
|
||||
}
|
||||
};
|
||||
|
||||
let result =
|
||||
unify(self.infcx, *environment, ty::Variance::Invariant, goal, &consequence)
|
||||
.map_err(|_| NoSolution)?;
|
||||
|
||||
let mut ex_clause = ExClause {
|
||||
subst: subst.clone(),
|
||||
delayed_literals: vec![],
|
||||
constraints: vec![],
|
||||
subgoals: vec![],
|
||||
};
|
||||
|
||||
self.into_ex_clause(result, &mut ex_clause);
|
||||
|
||||
ex_clause.subgoals.extend(hypotheses.iter().map(|g| match g {
|
||||
GoalKind::Not(g) => Literal::Negative(environment.with(*g)),
|
||||
g => Literal::Positive(environment.with(*g)),
|
||||
}));
|
||||
|
||||
// If we have a goal of the form `T: 'a` or `'a: 'b`, then just
|
||||
// assume it is true (no subgoals) and register it as a constraint
|
||||
// instead.
|
||||
match goal {
|
||||
DomainGoal::Holds(WhereClause::RegionOutlives(pred)) => {
|
||||
assert_eq!(ex_clause.subgoals.len(), 0);
|
||||
ex_clause.constraints.push(ty::OutlivesPredicate(pred.0.into(), pred.1));
|
||||
}
|
||||
|
||||
DomainGoal::Holds(WhereClause::TypeOutlives(pred)) => {
|
||||
assert_eq!(ex_clause.subgoals.len(), 0);
|
||||
ex_clause.constraints.push(ty::OutlivesPredicate(pred.0.into(), pred.1));
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
|
||||
let canonical_ex_clause = self.canonicalize_ex_clause(&ex_clause);
|
||||
Ok(canonical_ex_clause)
|
||||
});
|
||||
|
||||
debug!("resolvent_clause: result = {:?}", result);
|
||||
result
|
||||
}
|
||||
|
||||
fn apply_answer_subst(
|
||||
&mut self,
|
||||
ex_clause: ChalkExClause<'tcx>,
|
||||
selected_goal: &InEnvironment<'tcx, Goal<'tcx>>,
|
||||
answer_table_goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
canonical_answer_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>,
|
||||
) -> Fallible<ChalkExClause<'tcx>> {
|
||||
debug!(
|
||||
"apply_answer_subst(ex_clause = {:?}, selected_goal = {:?})",
|
||||
self.infcx.resolve_vars_if_possible(&ex_clause),
|
||||
self.infcx.resolve_vars_if_possible(selected_goal)
|
||||
);
|
||||
|
||||
let (answer_subst, _) = self
|
||||
.infcx
|
||||
.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, canonical_answer_subst);
|
||||
|
||||
let mut substitutor = AnswerSubstitutor {
|
||||
infcx: self.infcx,
|
||||
environment: selected_goal.environment,
|
||||
answer_subst: answer_subst.subst,
|
||||
binder_index: ty::INNERMOST,
|
||||
ex_clause,
|
||||
};
|
||||
|
||||
substitutor.relate(&answer_table_goal.value, &selected_goal).map_err(|_| NoSolution)?;
|
||||
|
||||
let mut ex_clause = substitutor.ex_clause;
|
||||
ex_clause.constraints.extend(answer_subst.constraints);
|
||||
|
||||
debug!("apply_answer_subst: ex_clause = {:?}", ex_clause);
|
||||
Ok(ex_clause)
|
||||
}
|
||||
}
|
||||
|
||||
struct AnswerSubstitutor<'cx, 'tcx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
environment: Environment<'tcx>,
|
||||
answer_subst: CanonicalVarValues<'tcx>,
|
||||
binder_index: ty::DebruijnIndex,
|
||||
ex_clause: ChalkExClause<'tcx>,
|
||||
}
|
||||
|
||||
impl AnswerSubstitutor<'cx, 'tcx> {
|
||||
fn unify_free_answer_var(
|
||||
&mut self,
|
||||
answer_var: ty::BoundVar,
|
||||
pending: GenericArg<'tcx>,
|
||||
) -> RelateResult<'tcx, ()> {
|
||||
let answer_param = &self.answer_subst.var_values[answer_var];
|
||||
let pending =
|
||||
&ty::fold::shift_out_vars(self.infcx.tcx, &pending, self.binder_index.as_u32());
|
||||
|
||||
super::into_ex_clause(
|
||||
unify(self.infcx, self.environment, ty::Variance::Invariant, answer_param, pending)?,
|
||||
&mut self.ex_clause,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
// FIXME(oli-obk): learn chalk and create param envs
|
||||
ty::ParamEnv::empty()
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
"chalk_context::answer_substitutor"
|
||||
}
|
||||
|
||||
fn a_is_expected(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
_variance: ty::Variance,
|
||||
a: &T,
|
||||
b: &T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
// We don't care about variance.
|
||||
self.relate(a, b)
|
||||
}
|
||||
|
||||
fn binders<T: Relate<'tcx>>(
|
||||
&mut self,
|
||||
a: &ty::Binder<T>,
|
||||
b: &ty::Binder<T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<T>> {
|
||||
self.binder_index.shift_in(1);
|
||||
let result = self.relate(a.skip_binder(), b.skip_binder())?;
|
||||
self.binder_index.shift_out(1);
|
||||
Ok(ty::Binder::bind(result))
|
||||
}
|
||||
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let b = self.infcx.shallow_resolve(b);
|
||||
debug!("AnswerSubstitutor::tys(a = {:?}, b = {:?})", a, b);
|
||||
|
||||
if let &ty::Bound(debruijn, bound_ty) = &a.kind {
|
||||
// Free bound var
|
||||
if debruijn == self.binder_index {
|
||||
self.unify_free_answer_var(bound_ty.var, b.into())?;
|
||||
return Ok(b);
|
||||
}
|
||||
}
|
||||
|
||||
match (&a.kind, &b.kind) {
|
||||
(&ty::Bound(a_debruijn, a_bound), &ty::Bound(b_debruijn, b_bound)) => {
|
||||
assert_eq!(a_debruijn, b_debruijn);
|
||||
assert_eq!(a_bound.var, b_bound.var);
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
// Those should have been canonicalized away.
|
||||
(ty::Placeholder(..), _) => {
|
||||
bug!("unexpected placeholder ty in `AnswerSubstitutor`: {:?} ", a);
|
||||
}
|
||||
|
||||
// Everything else should just be a perfect match as well,
|
||||
// and we forbid inference variables.
|
||||
_ => match ty::relate::super_relate_tys(self, a, b) {
|
||||
Ok(ty) => Ok(ty),
|
||||
Err(err) => bug!("type mismatch in `AnswerSubstitutor`: {}", err),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn regions(
|
||||
&mut self,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
let b = match b {
|
||||
&ty::ReVar(vid) => self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.infcx.tcx, vid),
|
||||
|
||||
other => other,
|
||||
};
|
||||
|
||||
if let &ty::ReLateBound(debruijn, bound) = a {
|
||||
// Free bound region
|
||||
if debruijn == self.binder_index {
|
||||
self.unify_free_answer_var(bound.assert_bound_var(), b.into())?;
|
||||
return Ok(b);
|
||||
}
|
||||
}
|
||||
|
||||
match (a, b) {
|
||||
(&ty::ReLateBound(a_debruijn, a_bound), &ty::ReLateBound(b_debruijn, b_bound)) => {
|
||||
assert_eq!(a_debruijn, b_debruijn);
|
||||
assert_eq!(a_bound.assert_bound_var(), b_bound.assert_bound_var());
|
||||
}
|
||||
|
||||
(ty::ReStatic, ty::ReStatic) | (ty::ReErased, ty::ReErased) => (),
|
||||
|
||||
(ty::ReEmpty(a_ui), ty::ReEmpty(b_ui)) => {
|
||||
assert_eq!(a_ui, b_ui);
|
||||
}
|
||||
|
||||
(&ty::ReFree(a_free), &ty::ReFree(b_free)) => {
|
||||
assert_eq!(a_free, b_free);
|
||||
}
|
||||
|
||||
_ => bug!("unexpected regions in `AnswerSubstitutor`: {:?}, {:?}", a, b),
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn consts(
|
||||
&mut self,
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
|
||||
if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), .. } = a {
|
||||
if *debruijn == self.binder_index {
|
||||
self.unify_free_answer_var(*bound_ct, b.into())?;
|
||||
return Ok(b);
|
||||
}
|
||||
}
|
||||
|
||||
match (a, b) {
|
||||
(
|
||||
ty::Const { val: ty::ConstKind::Bound(a_debruijn, a_bound), .. },
|
||||
ty::Const { val: ty::ConstKind::Bound(b_debruijn, b_bound), .. },
|
||||
) => {
|
||||
assert_eq!(a_debruijn, b_debruijn);
|
||||
assert_eq!(a_bound, b_bound);
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
// Everything else should just be a perfect match as well,
|
||||
// and we forbid inference variables.
|
||||
_ => match ty::relate::super_relate_consts(self, a, b) {
|
||||
Ok(ct) => Ok(ct),
|
||||
Err(err) => bug!("const mismatch in `AnswerSubstitutor`: {}", err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
use rustc::ty;
|
||||
use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin};
|
||||
use rustc_infer::traits::{DomainGoal, Environment, Goal, InEnvironment};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
crate struct UnificationResult<'tcx> {
|
||||
crate goals: Vec<InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
crate constraints: Vec<super::RegionConstraint<'tcx>>,
|
||||
}
|
||||
|
||||
crate fn unify<'me, 'tcx, T: Relate<'tcx>>(
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
environment: Environment<'tcx>,
|
||||
variance: ty::Variance,
|
||||
a: &T,
|
||||
b: &T,
|
||||
) -> RelateResult<'tcx, UnificationResult<'tcx>> {
|
||||
debug!(
|
||||
"unify(
|
||||
a = {:?},
|
||||
b = {:?},
|
||||
environment = {:?},
|
||||
)",
|
||||
a, b, environment
|
||||
);
|
||||
|
||||
let mut delegate = ChalkTypeRelatingDelegate::new(infcx, environment);
|
||||
|
||||
TypeRelating::new(infcx, &mut delegate, variance).relate(a, b)?;
|
||||
|
||||
debug!("unify: goals = {:?}, constraints = {:?}", delegate.goals, delegate.constraints);
|
||||
|
||||
Ok(UnificationResult { goals: delegate.goals, constraints: delegate.constraints })
|
||||
}
|
||||
|
||||
struct ChalkTypeRelatingDelegate<'me, 'tcx> {
|
||||
infcx: &'me InferCtxt<'me, 'tcx>,
|
||||
environment: Environment<'tcx>,
|
||||
goals: Vec<InEnvironment<'tcx, Goal<'tcx>>>,
|
||||
constraints: Vec<super::RegionConstraint<'tcx>>,
|
||||
}
|
||||
|
||||
impl ChalkTypeRelatingDelegate<'me, 'tcx> {
|
||||
fn new(infcx: &'me InferCtxt<'me, 'tcx>, environment: Environment<'tcx>) -> Self {
|
||||
Self { infcx, environment, goals: Vec::new(), constraints: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeRelatingDelegate<'tcx> for &mut ChalkTypeRelatingDelegate<'_, 'tcx> {
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex {
|
||||
self.infcx.create_next_universe()
|
||||
}
|
||||
|
||||
fn next_existential_region_var(&mut self, _was_placeholder: bool) -> ty::Region<'tcx> {
|
||||
self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
|
||||
}
|
||||
|
||||
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
|
||||
self.infcx.tcx.mk_region(ty::RePlaceholder(placeholder))
|
||||
}
|
||||
|
||||
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
|
||||
self.infcx
|
||||
.next_region_var_in_universe(RegionVariableOrigin::MiscVariable(DUMMY_SP), universe)
|
||||
}
|
||||
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
|
||||
self.constraints.push(ty::OutlivesPredicate(sup.into(), sub));
|
||||
}
|
||||
|
||||
fn push_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) {
|
||||
let goal = self.environment.with(self.infcx.tcx.mk_goal(domain_goal.into_goal()));
|
||||
self.goals.push(goal);
|
||||
}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Lazy
|
||||
}
|
||||
|
||||
fn forbid_inference_vars() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
//! Utilities for creating generic types with bound vars in place of parameter values.
|
||||
|
||||
use rustc::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_target::spec::abi;
|
||||
|
||||
crate fn bound(tcx: TyCtxt<'tcx>, index: u32) -> Ty<'tcx> {
|
||||
let ty = ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(index).into());
|
||||
tcx.mk_ty(ty)
|
||||
}
|
||||
|
||||
crate fn raw_ptr(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> {
|
||||
tcx.mk_ptr(ty::TypeAndMut { ty: bound(tcx, 0), mutbl })
|
||||
}
|
||||
|
||||
crate fn fn_ptr(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
arity_and_output: usize,
|
||||
c_variadic: bool,
|
||||
unsafety: hir::Unsafety,
|
||||
abi: abi::Abi,
|
||||
) -> Ty<'tcx> {
|
||||
let inputs_and_output = tcx.mk_type_list(
|
||||
(0..arity_and_output)
|
||||
.map(|i| ty::BoundVar::from(i))
|
||||
// DebruijnIndex(1) because we are going to inject these in a `PolyFnSig`
|
||||
.map(|var| tcx.mk_ty(ty::Bound(ty::DebruijnIndex::from(1usize), var.into()))),
|
||||
);
|
||||
|
||||
let fn_sig = ty::Binder::bind(ty::FnSig { inputs_and_output, c_variadic, unsafety, abi });
|
||||
tcx.mk_fn_ptr(fn_sig)
|
||||
}
|
||||
|
||||
crate fn type_list(tcx: TyCtxt<'tcx>, arity: usize) -> SubstsRef<'tcx> {
|
||||
tcx.mk_substs(
|
||||
(0..arity)
|
||||
.map(|i| ty::BoundVar::from(i))
|
||||
.map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into())))
|
||||
.map(|ty| GenericArg::from(ty)),
|
||||
)
|
||||
}
|
||||
|
||||
crate fn ref_ty(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> {
|
||||
let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0)));
|
||||
|
||||
tcx.mk_ref(region, ty::TypeAndMut { ty: bound(tcx, 1), mutbl })
|
||||
}
|
||||
|
||||
crate fn fn_def(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> {
|
||||
tcx.mk_ty(ty::FnDef(def_id, InternalSubsts::bound_vars_for_item(tcx, def_id)))
|
||||
}
|
||||
|
||||
crate fn closure(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> {
|
||||
tcx.mk_closure(def_id, InternalSubsts::bound_vars_for_item(tcx, def_id))
|
||||
}
|
||||
|
||||
crate fn generator(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> {
|
||||
tcx.mk_generator(
|
||||
def_id,
|
||||
InternalSubsts::bound_vars_for_item(tcx, def_id),
|
||||
hir::Movability::Movable,
|
||||
)
|
||||
}
|
|
@ -11,10 +11,8 @@ extern crate log;
|
|||
#[macro_use]
|
||||
extern crate rustc;
|
||||
|
||||
mod chalk_context;
|
||||
mod dropck_outlives;
|
||||
mod evaluate_obligation;
|
||||
mod generic_types;
|
||||
mod implied_outlives_bounds;
|
||||
pub mod lowering;
|
||||
mod normalize_erasing_regions;
|
||||
|
@ -28,7 +26,6 @@ pub fn provide(p: &mut Providers<'_>) {
|
|||
evaluate_obligation::provide(p);
|
||||
implied_outlives_bounds::provide(p);
|
||||
lowering::provide(p);
|
||||
chalk_context::provide(p);
|
||||
normalize_projection_ty::provide(p);
|
||||
normalize_erasing_regions::provide(p);
|
||||
type_op::provide(p);
|
||||
|
|
|
@ -252,11 +252,8 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
|
|||
// are any errors at that point, so after type checking you can be
|
||||
// sure that this will succeed without errors anyway.
|
||||
|
||||
let unnormalized_env = ty::ParamEnv::new(
|
||||
tcx.intern_predicates(&predicates),
|
||||
traits::Reveal::UserFacing,
|
||||
tcx.sess.opts.debugging_opts.chalk.then_some(def_id),
|
||||
);
|
||||
let unnormalized_env =
|
||||
ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing, None);
|
||||
|
||||
let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| {
|
||||
tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
|
||||
impl Foo for i32 { }
|
||||
|
||||
impl Foo for u32 { }
|
||||
|
||||
fn gimme<F: Foo>() { }
|
||||
|
||||
// Note: this also tests that `std::process::Termination` is implemented for `()`.
|
||||
fn main() {
|
||||
gimme::<i32>();
|
||||
gimme::<u32>();
|
||||
gimme::<f32>(); //~ERROR the trait bound `f32: Foo` is not satisfied
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
|
||||
impl<T> Foo for (T, u32) { }
|
||||
|
||||
fn gimme<F: Foo>() { }
|
||||
|
||||
fn foo<T>() {
|
||||
gimme::<(T, u32)>();
|
||||
gimme::<(Option<T>, u32)>();
|
||||
gimme::<(Option<T>, f32)>(); //~ ERROR
|
||||
}
|
||||
|
||||
fn main() {
|
||||
gimme::<(i32, u32)>();
|
||||
gimme::<(i32, f32)>(); //~ ERROR
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo: Sized { }
|
||||
|
||||
trait Bar {
|
||||
type Item: Foo;
|
||||
}
|
||||
|
||||
impl Foo for i32 { }
|
||||
|
||||
impl Foo for str { }
|
||||
//~^ ERROR the size for values of type `str` cannot be known at compilation time
|
||||
|
||||
// Implicit `T: Sized` bound.
|
||||
impl<T> Foo for Option<T> { }
|
||||
|
||||
impl Bar for () {
|
||||
type Item = i32;
|
||||
}
|
||||
|
||||
impl<T> Bar for Option<T> {
|
||||
type Item = Option<T>;
|
||||
}
|
||||
|
||||
impl Bar for f32 {
|
||||
//~^ ERROR the trait bound `f32: Foo` is not satisfied
|
||||
type Item = f32;
|
||||
//~^ ERROR the trait bound `f32: Foo` is not satisfied
|
||||
}
|
||||
|
||||
trait Baz<U: ?Sized> where U: Foo { }
|
||||
|
||||
impl Baz<i32> for i32 { }
|
||||
|
||||
impl Baz<f32> for f32 { }
|
||||
//~^ ERROR the trait bound `f32: Foo` is not satisfied
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// compile-flags: -Z chalk
|
||||
|
||||
#![feature(trivial_bounds)]
|
||||
|
||||
trait Bar {
|
||||
fn foo();
|
||||
}
|
||||
trait Foo: Bar { }
|
||||
|
||||
struct S where S: Foo;
|
||||
|
||||
impl Foo for S {
|
||||
}
|
||||
|
||||
fn bar<T: Bar>() {
|
||||
T::foo();
|
||||
}
|
||||
|
||||
fn foo<T: Foo>() {
|
||||
bar::<T>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// For some reason, the error is duplicated...
|
||||
|
||||
foo::<S>() //~ ERROR the type `S` is not well-formed (chalk)
|
||||
//~^ ERROR the type `S` is not well-formed (chalk)
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
|
||||
struct S<T: Foo> {
|
||||
x: T,
|
||||
}
|
||||
|
||||
impl Foo for i32 { }
|
||||
impl<T> Foo for Option<T> { }
|
||||
|
||||
fn main() {
|
||||
let s = S {
|
||||
x: 5,
|
||||
};
|
||||
|
||||
let s = S { //~ ERROR the trait bound `{float}: Foo` is not satisfied
|
||||
x: 5.0,
|
||||
};
|
||||
|
||||
let s = S {
|
||||
x: Some(5.0),
|
||||
};
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
// Test that `Clone` is correctly implemented for builtin types.
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct S(i32);
|
||||
|
||||
fn test_clone<T: Clone>(arg: T) {
|
||||
let _ = arg.clone();
|
||||
}
|
||||
|
||||
fn test_copy<T: Copy>(arg: T) {
|
||||
let _ = arg;
|
||||
let _ = arg;
|
||||
}
|
||||
|
||||
fn test_copy_clone<T: Copy + Clone>(arg: T) {
|
||||
test_copy(arg);
|
||||
test_clone(arg);
|
||||
}
|
||||
|
||||
fn foo() { }
|
||||
|
||||
fn main() {
|
||||
test_copy_clone(foo);
|
||||
let f: fn() = foo;
|
||||
test_copy_clone(f);
|
||||
// FIXME: add closures when they're considered WF
|
||||
test_copy_clone([1; 56]);
|
||||
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
|
||||
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1));
|
||||
test_copy_clone(());
|
||||
test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ()));
|
||||
|
||||
let a = (
|
||||
(S(1), S(0)),
|
||||
(
|
||||
(S(0), S(0), S(1)),
|
||||
S(0)
|
||||
)
|
||||
);
|
||||
test_copy_clone(a);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
|
||||
impl Foo for i32 { }
|
||||
|
||||
struct S<T: Foo> {
|
||||
x: T,
|
||||
}
|
||||
|
||||
fn only_foo<T: Foo>(_x: &T) { }
|
||||
|
||||
impl<T> S<T> {
|
||||
// Test that we have the correct environment inside an inherent method.
|
||||
fn dummy_foo(&self) {
|
||||
only_foo(&self.x)
|
||||
}
|
||||
}
|
||||
|
||||
trait Bar { }
|
||||
impl Bar for u32 { }
|
||||
|
||||
fn only_bar<T: Bar>() { }
|
||||
|
||||
impl<T> S<T> {
|
||||
// Test that the environment of `dummy_bar` adds up with the environment
|
||||
// of the inherent impl.
|
||||
fn dummy_bar<U: Bar>(&self) {
|
||||
only_foo(&self.x);
|
||||
only_bar::<U>();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = S {
|
||||
x: 5,
|
||||
};
|
||||
|
||||
s.dummy_foo();
|
||||
s.dummy_bar::<u32>();
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Foo { }
|
||||
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
trait Bar where Self: Foo { }
|
||||
|
||||
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
|
||||
fn bar<T: Bar + ?Sized>() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_env1.rs:6:1
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<Self> { FromEnv(Self: Foo) :- FromEnv(Self: Bar). }
|
||||
= note: forall<Self> { Implemented(Self: Bar) :- FromEnv(Self: Bar). }
|
||||
= note: forall<Self> { WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo). }
|
||||
|
||||
error: program clause dump
|
||||
--> $DIR/lower_env1.rs:9:1
|
||||
|
|
||||
LL | #[rustc_dump_env_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<Self> { FromEnv(Self: Foo) :- FromEnv(Self: Bar). }
|
||||
= note: forall<Self> { Implemented(Self: Bar) :- FromEnv(Self: Bar). }
|
||||
= note: forall<Self> { Implemented(Self: Foo) :- FromEnv(Self: Foo). }
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Foo { }
|
||||
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
struct S<'a, T: ?Sized> where T: Foo {
|
||||
data: &'a T,
|
||||
}
|
||||
|
||||
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
|
||||
fn bar<T: Foo>(_x: S<'_, T>) { // note that we have an implicit `T: Sized` bound
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_env2.rs:6:1
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). }
|
||||
= note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(S<'a, T>). }
|
||||
= note: forall<'a, T> { WellFormed(S<'a, T>) :- WellFormed(T: Foo), TypeOutlives(T: 'a). }
|
||||
|
||||
error: program clause dump
|
||||
--> $DIR/lower_env2.rs:11:1
|
||||
|
|
||||
LL | #[rustc_dump_env_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). }
|
||||
= note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(S<'a, T>). }
|
||||
= note: forall<Self> { Implemented(Self: Foo) :- FromEnv(Self: Foo). }
|
||||
= note: forall<Self> { Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). }
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
trait Foo {
|
||||
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
impl<T> Foo for T where T: Clone {
|
||||
#[rustc_dump_env_program_clauses] //~ ERROR program clause dump
|
||||
fn foo(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_env3.rs:5:5
|
||||
|
|
||||
LL | #[rustc_dump_env_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<Self> { Implemented(Self: Foo) :- FromEnv(Self: Foo). }
|
||||
|
||||
error: program clause dump
|
||||
--> $DIR/lower_env3.rs:10:5
|
||||
|
|
||||
LL | #[rustc_dump_env_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<Self> { FromEnv(Self: std::marker::Sized) :- FromEnv(Self: std::clone::Clone). }
|
||||
= note: forall<Self> { Implemented(Self: std::clone::Clone) :- FromEnv(Self: std::clone::Clone). }
|
||||
= note: forall<Self> { Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). }
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
|
||||
trait Foo { }
|
||||
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }
|
||||
|
||||
trait Bar {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Bar for T where T: Iterator<Item = i32> {
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
type Assoc = Vec<T>;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("hello");
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_impl.rs:5:1
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<T> { Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T: 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). }
|
||||
|
||||
error: program clause dump
|
||||
--> $DIR/lower_impl.rs:13:5
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<T> { Normalize(<T as Bar>::Assoc -> std::vec::Vec<T>) :- Implemented(T: Bar). }
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
struct Foo<'a, T> where Box<T>: Clone {
|
||||
_x: std::marker::PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
fn main() { }
|
|
@ -1,13 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_struct.rs:3:1
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<'a, T> { FromEnv(T: std::marker::Sized) :- FromEnv(Foo<'a, T>). }
|
||||
= note: forall<'a, T> { FromEnv(std::boxed::Box<T>: std::clone::Clone) :- FromEnv(Foo<'a, T>). }
|
||||
= note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(Foo<'a, T>). }
|
||||
= note: forall<'a, T> { WellFormed(Foo<'a, T>) :- WellFormed(T: std::marker::Sized), WellFormed(std::boxed::Box<T>: std::clone::Clone), TypeOutlives(T: 'a). }
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
|
||||
trait Bar { }
|
||||
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
trait Foo<S, T: ?Sized> {
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
type Assoc: Bar + ?Sized;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("hello");
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_trait.rs:5:1
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<Self, S, T> { FromEnv(<Self as Foo<S, T>>::Assoc: Bar) :- FromEnv(Self: Foo<S, T>). }
|
||||
= note: forall<Self, S, T> { FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T>). }
|
||||
= note: forall<Self, S, T> { Implemented(Self: Foo<S, T>) :- FromEnv(Self: Foo<S, T>). }
|
||||
= note: forall<Self, S, T> { WellFormed(Self: Foo<S, T>) :- Implemented(Self: Foo<S, T>), WellFormed(S: std::marker::Sized), WellFormed(<Self as Foo<S, T>>::Assoc: Bar). }
|
||||
|
||||
error: program clause dump
|
||||
--> $DIR/lower_trait.rs:7:5
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<Self, S, T, ^3> { ProjectionEq(<Self as Foo<S, T>>::Assoc == ^3) :- Normalize(<Self as Foo<S, T>>::Assoc -> ^3). }
|
||||
= note: forall<Self, S, T> { FromEnv(Self: Foo<S, T>) :- FromEnv(Unnormalized(<Self as Foo<S, T>>::Assoc)). }
|
||||
= note: forall<Self, S, T> { ProjectionEq(<Self as Foo<S, T>>::Assoc == Unnormalized(<Self as Foo<S, T>>::Assoc)). }
|
||||
= note: forall<Self, S, T> { WellFormed(Unnormalized(<Self as Foo<S, T>>::Assoc)) :- WellFormed(Self: Foo<S, T>). }
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
trait Foo<F: ?Sized> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("hello");
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_trait_higher_rank.rs:3:1
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<'a, Self, F> { FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>). }
|
||||
= note: forall<'a, Self, F> { ProjectionEq(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>). }
|
||||
= note: forall<Self, F> { Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>). }
|
||||
= note: forall<Self, F> { WellFormed(Self: Foo<F>) :- Implemented(Self: Foo<F>), forall<'a> { WellFormed(F: std::ops::Fn<(&'a (u8, u16),)>) }, forall<'a> { ProjectionEq(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) }. }
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::borrow::Borrow;
|
||||
|
||||
#[rustc_dump_program_clauses] //~ ERROR program clause dump
|
||||
trait Foo<'a, 'b, T, U>
|
||||
where
|
||||
T: Borrow<U> + ?Sized,
|
||||
U: ?Sized + 'b,
|
||||
'a: 'b,
|
||||
Box<T>:, // NOTE(#53696) this checks an empty list of bounds.
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("hello");
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
error: program clause dump
|
||||
--> $DIR/lower_trait_where_clause.rs:5:1
|
||||
|
|
||||
LL | #[rustc_dump_program_clauses]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: forall<'a, 'b, Self, T, U> { FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, T, U>). }
|
||||
= note: forall<'a, 'b, Self, T, U> { Implemented(Self: Foo<'a, 'b, T, U>) :- FromEnv(Self: Foo<'a, 'b, T, U>). }
|
||||
= note: forall<'a, 'b, Self, T, U> { RegionOutlives('a: 'b) :- FromEnv(Self: Foo<'a, 'b, T, U>). }
|
||||
= note: forall<'a, 'b, Self, T, U> { TypeOutlives(U: 'b) :- FromEnv(Self: Foo<'a, 'b, T, U>). }
|
||||
= note: forall<'a, 'b, Self, T, U> { TypeOutlives(std::boxed::Box<T>: '<empty>) :- FromEnv(Self: Foo<'a, 'b, T, U>). }
|
||||
= note: forall<'a, 'b, Self, T, U> { WellFormed(Self: Foo<'a, 'b, T, U>) :- Implemented(Self: Foo<'a, 'b, T, U>), WellFormed(T: std::borrow::Borrow<U>), TypeOutlives(U: 'b), RegionOutlives('a: 'b), TypeOutlives(std::boxed::Box<T>: '<empty>). }
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
|
||||
trait Bar {
|
||||
type Item: Foo;
|
||||
}
|
||||
|
||||
impl Foo for i32 { }
|
||||
impl Bar for i32 {
|
||||
type Item = i32;
|
||||
}
|
||||
|
||||
fn only_foo<T: Foo>() { }
|
||||
|
||||
fn only_bar<T: Bar>() {
|
||||
// `T` implements `Bar` hence `<T as Bar>::Item` must also implement `Bar`
|
||||
only_foo::<T::Item>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
only_bar::<i32>();
|
||||
only_foo::<<i32 as Bar>::Item>();
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
trait Bar: Foo { }
|
||||
|
||||
impl Foo for i32 { }
|
||||
impl Bar for i32 { }
|
||||
|
||||
fn only_foo<T: Foo>() { }
|
||||
|
||||
fn only_bar<T: Bar>() {
|
||||
// `T` implements `Bar` hence `T` must also implement `Foo`
|
||||
only_foo::<T>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
only_bar::<i32>()
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
trait Bar<U> where U: Foo { }
|
||||
|
||||
impl Foo for i32 { }
|
||||
impl Bar<i32> for i32 { }
|
||||
|
||||
fn only_foo<T: Foo>() { }
|
||||
|
||||
fn only_bar<U, T: Bar<U>>() {
|
||||
only_foo::<U>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
only_bar::<i32, i32>()
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
trait Eq { }
|
||||
trait Hash: Eq { }
|
||||
|
||||
impl Eq for i32 { }
|
||||
impl Hash for i32 { }
|
||||
|
||||
struct Set<T: Hash> {
|
||||
_x: T,
|
||||
}
|
||||
|
||||
fn only_eq<T: Eq>() { }
|
||||
|
||||
fn take_a_set<T>(_: &Set<T>) {
|
||||
// `Set<T>` is an input type of `take_a_set`, hence we know that
|
||||
// `T` must implement `Hash`, and we know in turn that `T` must
|
||||
// implement `Eq`.
|
||||
only_eq::<T>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let set = Set {
|
||||
_x: 5,
|
||||
};
|
||||
|
||||
take_a_set(&set);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
// compile-flags: -Z chalk
|
||||
|
||||
trait Foo { }
|
||||
impl Foo for i32 { }
|
||||
|
||||
trait Bar { }
|
||||
impl Bar for i32 { }
|
||||
impl Bar for u32 { }
|
||||
|
||||
fn only_foo<T: Foo>(_x: T) { }
|
||||
|
||||
fn only_bar<T: Bar>(_x: T) { }
|
||||
|
||||
fn main() {
|
||||
let x = 5.0;
|
||||
|
||||
// The only type which implements `Foo` is `i32`, so the chalk trait solver
|
||||
// is expecting a variable of type `i32`. This behavior differs from the
|
||||
// old-style trait solver. I guess this will change, that's why I'm
|
||||
// adding that test.
|
||||
only_foo(x); //~ ERROR mismatched types
|
||||
|
||||
// Here we have two solutions so we get back the behavior of the old-style
|
||||
// trait solver.
|
||||
only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/type_inference.rs:21:14
|
||||
|
|
||||
LL | only_foo(x);
|
||||
| ^ expected `i32`, found floating-point number
|
||||
|
||||
error[E0277]: the trait bound `{float}: Bar` is not satisfied
|
||||
--> $DIR/type_inference.rs:25:5
|
||||
|
|
||||
LL | fn only_bar<T: Bar>(_x: T) { }
|
||||
| -------- --- required by this bound in `only_bar`
|
||||
...
|
||||
LL | only_bar(x);
|
||||
| ^^^^^^^^ the trait `Bar` is not implemented for `{float}`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<i32 as Bar>
|
||||
<u32 as Bar>
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
|
@ -1,10 +0,0 @@
|
|||
// run-pass
|
||||
// compile-flags: -Z chalk
|
||||
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
|
||||
pub struct Foo<T, const N: usize>([T; N]);
|
||||
impl<T, const N: usize> Foo<T, {N}> {}
|
||||
|
||||
fn main() {}
|
|
@ -1,8 +0,0 @@
|
|||
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
|
||||
--> $DIR/issue-65675.rs:4:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
Loading…
Add table
Reference in a new issue