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:
bors 2020-03-03 04:31:01 +00:00
commit 9381e8178b
53 changed files with 20 additions and 2860 deletions

View file

@ -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",

View file

@ -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" }

View file

@ -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>

View file

@ -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.

View file

@ -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,
}

View file

@ -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,

View file

@ -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()
}
}

View file

@ -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())
}
}

View file

@ -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(..) => {

View file

@ -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.

View file

@ -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 })
}

View file

@ -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],

View file

@ -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" }

View file

@ -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))
}

View file

@ -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),
}
}

View file

@ -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
}
}

View file

@ -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))
}

View file

@ -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),
},
}
}
}

View file

@ -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
}
}

View file

@ -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,
)
}

View file

@ -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);

View file

@ -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)

View file

@ -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
}

View file

@ -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
}

View file

@ -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() {
}

View file

@ -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)
}

View file

@ -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),
};
}

View file

@ -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);
}

View file

@ -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>();
}

View file

@ -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() {
}

View file

@ -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

View file

@ -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() {
}

View file

@ -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

View file

@ -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() {
}

View file

@ -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

View file

@ -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");
}

View file

@ -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

View file

@ -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() { }

View file

@ -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

View file

@ -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");
}

View file

@ -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

View file

@ -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");
}

View file

@ -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

View file

@ -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");
}

View file

@ -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

View file

@ -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>();
}

View file

@ -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>()
}

View file

@ -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>()
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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