Rollup merge of #71758 - jackh726:chalk-remove, r=jackh726
Remove leftover chalk types Split out from #69406 Since the other PR is having memory problems with `parallel-compiler = true`, figured I should split this out. Surprisingly, this actually changes some errors, and I'm not quite sure why. r? @nikomatsakis
This commit is contained in:
commit
8aad12b87d
@ -16,7 +16,7 @@ use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelating
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::{InferCtxt, InferOk, InferResult, NLLRegionVariableOrigin};
|
||||
use crate::traits::query::{Fallible, NoSolution};
|
||||
use crate::traits::{DomainGoal, TraitEngine};
|
||||
use crate::traits::TraitEngine;
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_index::vec::Idx;
|
||||
@ -671,10 +671,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
|
||||
});
|
||||
}
|
||||
|
||||
fn push_domain_goal(&mut self, _: DomainGoal<'tcx>) {
|
||||
bug!("should never be invoked with eager normalization")
|
||||
}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::{ConstVarValue, ConstVariableValue};
|
||||
use crate::traits::DomainGoal;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
|
||||
@ -78,10 +77,6 @@ pub trait TypeRelatingDelegate<'tcx> {
|
||||
/// delegate.
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
|
||||
|
||||
/// Push a domain goal that will need to be proved for the two types to
|
||||
/// be related. Used for lazy normalization.
|
||||
fn push_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>);
|
||||
|
||||
/// Creates a new universe index. Used when instantiating placeholders.
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex;
|
||||
|
||||
@ -265,7 +260,6 @@ where
|
||||
value_ty: Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::traits::WhereClause;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
match value_ty.kind {
|
||||
@ -279,12 +273,7 @@ where
|
||||
var
|
||||
}
|
||||
|
||||
_ => {
|
||||
let projection = ty::ProjectionPredicate { projection_ty, ty: value_ty };
|
||||
self.delegate
|
||||
.push_domain_goal(DomainGoal::Holds(WhereClause::ProjectionEq(projection)));
|
||||
value_ty
|
||||
}
|
||||
_ => bug!("should never be invoked with eager normalization"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -838,10 +838,6 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
|
||||
tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
|
||||
});
|
||||
|
||||
sess.time("dumping_chalk_like_clauses", || {
|
||||
rustc_traits::lowering::dump_program_clauses(tcx);
|
||||
});
|
||||
|
||||
sess.time("MIR_effect_checking", || {
|
||||
for def_id in tcx.body_owners() {
|
||||
mir::transform::check_unsafety::check_unsafety(tcx, def_id.to_def_id())
|
||||
|
@ -51,7 +51,6 @@
|
||||
|
||||
use crate::mir;
|
||||
use crate::mir::interpret::{GlobalId, LitToConstInput};
|
||||
use crate::traits;
|
||||
use crate::traits::query::{
|
||||
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
|
||||
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::dep_graph::SerializedDepNodeIndex;
|
||||
use crate::mir;
|
||||
use crate::mir::interpret::{GlobalId, LitToConstInput};
|
||||
use crate::traits;
|
||||
use crate::traits::query::{
|
||||
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
|
||||
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
|
||||
@ -224,19 +223,6 @@ rustc_queries! {
|
||||
anon
|
||||
desc { "erasing regions from `{:?}`", ty }
|
||||
}
|
||||
|
||||
query program_clauses_for(_: DefId) -> Clauses<'tcx> {
|
||||
desc { "generating chalk-style clauses" }
|
||||
}
|
||||
|
||||
query program_clauses_for_env(_: traits::Environment<'tcx>) -> Clauses<'tcx> {
|
||||
desc { "generating chalk-style clauses for environment" }
|
||||
}
|
||||
|
||||
// Get the chalk-style environment of the given item.
|
||||
query environment(_: DefId) -> traits::Environment<'tcx> {
|
||||
desc { "return a chalk-style environment" }
|
||||
}
|
||||
}
|
||||
|
||||
Linking {
|
||||
|
@ -9,7 +9,7 @@ mod structural_impls;
|
||||
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::ty::{self, AdtKind, List, Ty, TyCtxt};
|
||||
use crate::ty::{self, AdtKind, Ty, TyCtxt};
|
||||
|
||||
use rustc_ast::ast;
|
||||
use rustc_hir as hir;
|
||||
@ -307,162 +307,6 @@ pub struct DerivedObligationCause<'tcx> {
|
||||
pub parent_code: Rc<ObligationCauseCode<'tcx>>,
|
||||
}
|
||||
|
||||
/// The following types:
|
||||
/// * `WhereClause`,
|
||||
/// * `WellFormed`,
|
||||
/// * `FromEnv`,
|
||||
/// * `DomainGoal`,
|
||||
/// * `Goal`,
|
||||
/// * `Clause`,
|
||||
/// * `Environment`,
|
||||
/// * `InEnvironment`,
|
||||
/// are used for representing the trait system in the form of
|
||||
/// logic programming clauses. They are part of the interface
|
||||
/// for the chalk SLG solver.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
|
||||
pub enum WhereClause<'tcx> {
|
||||
Implemented(ty::TraitPredicate<'tcx>),
|
||||
ProjectionEq(ty::ProjectionPredicate<'tcx>),
|
||||
RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
|
||||
TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
|
||||
pub enum WellFormed<'tcx> {
|
||||
Trait(ty::TraitPredicate<'tcx>),
|
||||
Ty(Ty<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
|
||||
pub enum FromEnv<'tcx> {
|
||||
Trait(ty::TraitPredicate<'tcx>),
|
||||
Ty(Ty<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
|
||||
pub enum DomainGoal<'tcx> {
|
||||
Holds(WhereClause<'tcx>),
|
||||
WellFormed(WellFormed<'tcx>),
|
||||
FromEnv(FromEnv<'tcx>),
|
||||
Normalize(ty::ProjectionPredicate<'tcx>),
|
||||
}
|
||||
|
||||
pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
|
||||
pub enum QuantifierKind {
|
||||
Universal,
|
||||
Existential,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
|
||||
pub enum GoalKind<'tcx> {
|
||||
Implies(Clauses<'tcx>, Goal<'tcx>),
|
||||
And(Goal<'tcx>, Goal<'tcx>),
|
||||
Not(Goal<'tcx>),
|
||||
DomainGoal(DomainGoal<'tcx>),
|
||||
Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
|
||||
Subtype(Ty<'tcx>, Ty<'tcx>),
|
||||
CannotProve,
|
||||
}
|
||||
|
||||
pub type Goal<'tcx> = &'tcx GoalKind<'tcx>;
|
||||
|
||||
pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>;
|
||||
|
||||
impl<'tcx> DomainGoal<'tcx> {
|
||||
pub fn into_goal(self) -> GoalKind<'tcx> {
|
||||
GoalKind::DomainGoal(self)
|
||||
}
|
||||
|
||||
pub fn into_program_clause(self) -> ProgramClause<'tcx> {
|
||||
ProgramClause {
|
||||
goal: self,
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> GoalKind<'tcx> {
|
||||
pub fn from_poly_domain_goal(
|
||||
domain_goal: PolyDomainGoal<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> GoalKind<'tcx> {
|
||||
match domain_goal.no_bound_vars() {
|
||||
Some(p) => p.into_goal(),
|
||||
None => GoalKind::Quantified(
|
||||
QuantifierKind::Universal,
|
||||
domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary
|
||||
/// Harrop Formulas".
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
|
||||
pub enum Clause<'tcx> {
|
||||
Implies(ProgramClause<'tcx>),
|
||||
ForAll(ty::Binder<ProgramClause<'tcx>>),
|
||||
}
|
||||
|
||||
impl Clause<'tcx> {
|
||||
pub fn category(self) -> ProgramClauseCategory {
|
||||
match self {
|
||||
Clause::Implies(clause) => clause.category,
|
||||
Clause::ForAll(clause) => clause.skip_binder().category,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiple clauses.
|
||||
pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>;
|
||||
|
||||
/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
|
||||
/// that the domain goal `D` is true if `G1...Gn` are provable. This
|
||||
/// is equivalent to the implication `G1..Gn => D`; we usually write
|
||||
/// it with the reverse implication operator `:-` to emphasize the way
|
||||
/// that programs are actually solved (via backchaining, which starts
|
||||
/// with the goal to solve and proceeds from there).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
|
||||
pub struct ProgramClause<'tcx> {
|
||||
/// This goal will be considered true ...
|
||||
pub goal: DomainGoal<'tcx>,
|
||||
|
||||
/// ... if we can prove these hypotheses (there may be no hypotheses at all):
|
||||
pub hypotheses: Goals<'tcx>,
|
||||
|
||||
/// Useful for filtering clauses.
|
||||
pub category: ProgramClauseCategory,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
|
||||
pub enum ProgramClauseCategory {
|
||||
ImpliedBound,
|
||||
WellFormed,
|
||||
Other,
|
||||
}
|
||||
|
||||
/// A set of clauses that we assume to be true.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
|
||||
pub struct Environment<'tcx> {
|
||||
pub clauses: Clauses<'tcx>,
|
||||
}
|
||||
|
||||
impl Environment<'tcx> {
|
||||
pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> {
|
||||
InEnvironment { environment: self, goal }
|
||||
}
|
||||
}
|
||||
|
||||
/// Something (usually a goal), along with an environment.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
|
||||
pub struct InEnvironment<'tcx, G> {
|
||||
pub environment: Environment<'tcx>,
|
||||
pub goal: G,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TypeFoldable)]
|
||||
pub enum SelectionError<'tcx> {
|
||||
Unimplemented,
|
||||
|
@ -1,10 +1,6 @@
|
||||
use crate::traits;
|
||||
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use crate::ty::{self, Lift, Ty, TyCtxt};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use smallvec::SmallVec;
|
||||
use crate::ty::{Lift, TyCtxt};
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -106,295 +102,6 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for traits::WhereClause<'tcx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::WhereClause::*;
|
||||
|
||||
// Bypass `ty::print` because it does not print out anonymous regions.
|
||||
// FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`.
|
||||
fn write_region_name<'tcx>(
|
||||
r: ty::Region<'tcx>,
|
||||
fmt: &mut fmt::Formatter<'_>,
|
||||
) -> fmt::Result {
|
||||
match r {
|
||||
ty::ReLateBound(index, br) => match br {
|
||||
ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name),
|
||||
ty::BoundRegion::BrAnon(var) => {
|
||||
if *index == ty::INNERMOST {
|
||||
write!(fmt, "'^{}", var)
|
||||
} else {
|
||||
write!(fmt, "'^{}_{}", index.index(), var)
|
||||
}
|
||||
}
|
||||
_ => write!(fmt, "'_"),
|
||||
},
|
||||
|
||||
_ => write!(fmt, "{}", r),
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref),
|
||||
ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection),
|
||||
RegionOutlives(predicate) => {
|
||||
write!(fmt, "RegionOutlives({}: ", predicate.0)?;
|
||||
write_region_name(predicate.1, fmt)?;
|
||||
write!(fmt, ")")
|
||||
}
|
||||
TypeOutlives(predicate) => {
|
||||
write!(fmt, "TypeOutlives({}: ", predicate.0)?;
|
||||
write_region_name(predicate.1, fmt)?;
|
||||
write!(fmt, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for traits::WellFormed<'tcx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::WellFormed::*;
|
||||
|
||||
match self {
|
||||
Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref),
|
||||
Ty(ty) => write!(fmt, "WellFormed({})", ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for traits::FromEnv<'tcx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::FromEnv::*;
|
||||
|
||||
match self {
|
||||
Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref),
|
||||
Ty(ty) => write!(fmt, "FromEnv({})", ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::DomainGoal::*;
|
||||
|
||||
match self {
|
||||
Holds(wc) => write!(fmt, "{}", wc),
|
||||
WellFormed(wf) => write!(fmt, "{}", wf),
|
||||
FromEnv(from_env) => write!(fmt, "{}", from_env),
|
||||
Normalize(projection) => {
|
||||
write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for traits::QuantifierKind {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::QuantifierKind::*;
|
||||
|
||||
match self {
|
||||
Universal => write!(fmt, "forall"),
|
||||
Existential => write!(fmt, "exists"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect names for regions / types bound by a quantified goal / clause.
|
||||
/// This collector does not try to do anything clever like in `ty::print`, it's just used
|
||||
/// for debug output in tests anyway.
|
||||
struct BoundNamesCollector {
|
||||
// Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
|
||||
regions: BTreeSet<Symbol>,
|
||||
|
||||
// Sort by `BoundVar` index, so usually this should be equivalent to the order given
|
||||
// by the list of type parameters.
|
||||
types: BTreeMap<u32, Symbol>,
|
||||
|
||||
binder_index: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
impl BoundNamesCollector {
|
||||
fn new() -> Self {
|
||||
BoundNamesCollector {
|
||||
regions: BTreeSet::new(),
|
||||
types: BTreeMap::new(),
|
||||
binder_index: ty::INNERMOST,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.regions.is_empty() && self.types.is_empty()
|
||||
}
|
||||
|
||||
fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut start = true;
|
||||
for r in &self.regions {
|
||||
if !start {
|
||||
write!(fmt, ", ")?;
|
||||
}
|
||||
start = false;
|
||||
write!(fmt, "{}", r)?;
|
||||
}
|
||||
for t in self.types.values() {
|
||||
if !start {
|
||||
write!(fmt, ", ")?;
|
||||
}
|
||||
start = false;
|
||||
write!(fmt, "{}", t)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
|
||||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
|
||||
self.binder_index.shift_in(1);
|
||||
let result = t.super_visit_with(self);
|
||||
self.binder_index.shift_out(1);
|
||||
result
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
match t.kind {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
|
||||
self.types.insert(
|
||||
bound_ty.var.as_u32(),
|
||||
match bound_ty.kind {
|
||||
ty::BoundTyKind::Param(name) => name,
|
||||
ty::BoundTyKind::Anon => {
|
||||
Symbol::intern(&format!("^{}", bound_ty.var.as_u32()))
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
match c.val {
|
||||
ty::ConstKind::Bound(debruijn, bound_var) if debruijn == self.binder_index => {
|
||||
self.types.insert(
|
||||
bound_var.as_u32(),
|
||||
Symbol::intern(&format!("^{}", bound_var.as_u32())),
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||
match r {
|
||||
ty::ReLateBound(index, br) if *index == self.binder_index => match br {
|
||||
ty::BoundRegion::BrNamed(_, name) => {
|
||||
self.regions.insert(*name);
|
||||
}
|
||||
|
||||
ty::BoundRegion::BrAnon(var) => {
|
||||
self.regions.insert(Symbol::intern(&format!("'^{}", var)));
|
||||
}
|
||||
|
||||
_ => (),
|
||||
},
|
||||
|
||||
_ => (),
|
||||
};
|
||||
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for traits::Goal<'tcx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::GoalKind::*;
|
||||
|
||||
match self {
|
||||
Implies(hypotheses, goal) => {
|
||||
write!(fmt, "if (")?;
|
||||
for (index, hyp) in hypotheses.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(fmt, ", ")?;
|
||||
}
|
||||
write!(fmt, "{}", hyp)?;
|
||||
}
|
||||
write!(fmt, ") {{ {} }}", goal)
|
||||
}
|
||||
And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2),
|
||||
Not(goal) => write!(fmt, "not {{ {} }}", goal),
|
||||
DomainGoal(goal) => write!(fmt, "{}", goal),
|
||||
Quantified(qkind, goal) => {
|
||||
let mut collector = BoundNamesCollector::new();
|
||||
goal.skip_binder().visit_with(&mut collector);
|
||||
|
||||
if !collector.is_empty() {
|
||||
write!(fmt, "{}<", qkind)?;
|
||||
collector.write_names(fmt)?;
|
||||
write!(fmt, "> {{ ")?;
|
||||
}
|
||||
|
||||
write!(fmt, "{}", goal.skip_binder())?;
|
||||
|
||||
if !collector.is_empty() {
|
||||
write!(fmt, " }}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Subtype(a, b) => write!(fmt, "{} <: {}", a, b),
|
||||
CannotProve => write!(fmt, "CannotProve"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let traits::ProgramClause { goal, hypotheses, .. } = self;
|
||||
write!(fmt, "{}", goal)?;
|
||||
if !hypotheses.is_empty() {
|
||||
write!(fmt, " :- ")?;
|
||||
for (index, condition) in hypotheses.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(fmt, ", ")?;
|
||||
}
|
||||
write!(fmt, "{}", condition)?;
|
||||
}
|
||||
}
|
||||
write!(fmt, ".")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for traits::Clause<'tcx> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use crate::traits::Clause::*;
|
||||
|
||||
match self {
|
||||
Implies(clause) => write!(fmt, "{}", clause),
|
||||
ForAll(clause) => {
|
||||
let mut collector = BoundNamesCollector::new();
|
||||
clause.skip_binder().visit_with(&mut collector);
|
||||
|
||||
if !collector.is_empty() {
|
||||
write!(fmt, "forall<")?;
|
||||
collector.write_names(fmt)?;
|
||||
write!(fmt, "> {{ ")?;
|
||||
}
|
||||
|
||||
write!(fmt, "{}", clause.skip_binder())?;
|
||||
|
||||
if !collector.is_empty() {
|
||||
write!(fmt, " }}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Lift implementations
|
||||
|
||||
@ -592,63 +299,3 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> {
|
||||
type Lifted = traits::Environment<'tcx>;
|
||||
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
|
||||
type Lifted = traits::InEnvironment<'tcx, G::Lifted>;
|
||||
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.environment).and_then(|environment| {
|
||||
tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TypeFoldable implementations.
|
||||
|
||||
CloneTypeFoldableAndLiftImpls! {
|
||||
traits::QuantifierKind,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> {
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
|
||||
folder.tcx().intern_goals(&v)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.iter().any(|t| t.visit_with(visitor))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
let v = (**self).fold_with(folder);
|
||||
folder.tcx().mk_goal(v)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
(**self).visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
CloneTypeFoldableAndLiftImpls! {
|
||||
traits::ProgramClauseCategory,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> {
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
|
||||
folder.tcx().intern_clauses(&v)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.iter().any(|t| t.visit_with(visitor))
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ use crate::middle::stability;
|
||||
use crate::mir::interpret::{Allocation, ConstValue, Scalar};
|
||||
use crate::mir::{interpret, Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
|
||||
use crate::traits;
|
||||
use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
|
||||
use crate::ty::query;
|
||||
use crate::ty::steal::Steal;
|
||||
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
|
||||
@ -92,9 +91,6 @@ pub struct CtxtInterners<'tcx> {
|
||||
region: InternedSet<'tcx, RegionKind>,
|
||||
existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>,
|
||||
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
|
||||
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
|
||||
goal: InternedSet<'tcx, GoalKind<'tcx>>,
|
||||
goal_list: InternedSet<'tcx, List<Goal<'tcx>>>,
|
||||
projs: InternedSet<'tcx, List<ProjectionKind>>,
|
||||
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
|
||||
const_: InternedSet<'tcx, Const<'tcx>>,
|
||||
@ -111,9 +107,6 @@ impl<'tcx> CtxtInterners<'tcx> {
|
||||
existential_predicates: Default::default(),
|
||||
canonical_var_infos: Default::default(),
|
||||
predicates: Default::default(),
|
||||
clauses: Default::default(),
|
||||
goal: Default::default(),
|
||||
goal_list: Default::default(),
|
||||
projs: Default::default(),
|
||||
place_elems: Default::default(),
|
||||
const_: Default::default(),
|
||||
@ -1573,11 +1566,8 @@ macro_rules! nop_list_lift {
|
||||
|
||||
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
|
||||
nop_lift! {region; Region<'a> => Region<'tcx>}
|
||||
nop_lift! {goal; Goal<'a> => Goal<'tcx>}
|
||||
nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
|
||||
|
||||
nop_list_lift! {goal_list; Goal<'a> => Goal<'tcx>}
|
||||
nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>}
|
||||
nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
|
||||
nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>}
|
||||
nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>}
|
||||
@ -1988,12 +1978,6 @@ impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Borrow<GoalKind<'tcx>> for Interned<'tcx, GoalKind<'tcx>> {
|
||||
fn borrow<'a>(&'a self) -> &'a GoalKind<'tcx> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Borrow<[ExistentialPredicate<'tcx>]>
|
||||
for Interned<'tcx, List<ExistentialPredicate<'tcx>>>
|
||||
{
|
||||
@ -2014,18 +1998,6 @@ impl<'tcx> Borrow<Const<'tcx>> for Interned<'tcx, Const<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Borrow<[Clause<'tcx>]> for Interned<'tcx, List<Clause<'tcx>>> {
|
||||
fn borrow<'a>(&'a self) -> &'a [Clause<'tcx>] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Borrow<[Goal<'tcx>]> for Interned<'tcx, List<Goal<'tcx>>> {
|
||||
fn borrow<'a>(&'a self) -> &'a [Goal<'tcx>] {
|
||||
&self.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! direct_interners {
|
||||
($($name:ident: $method:ident($ty:ty)),+) => {
|
||||
$(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
|
||||
@ -2052,11 +2024,7 @@ macro_rules! direct_interners {
|
||||
}
|
||||
}
|
||||
|
||||
direct_interners!(
|
||||
region: mk_region(RegionKind),
|
||||
goal: mk_goal(GoalKind<'tcx>),
|
||||
const_: mk_const(Const<'tcx>)
|
||||
);
|
||||
direct_interners!(region: mk_region(RegionKind), const_: mk_const(Const<'tcx>));
|
||||
|
||||
macro_rules! slice_interners {
|
||||
($($field:ident: $method:ident($ty:ty)),+) => (
|
||||
@ -2076,8 +2044,6 @@ slice_interners!(
|
||||
canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo),
|
||||
existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>),
|
||||
predicates: _intern_predicates(Predicate<'tcx>),
|
||||
clauses: _intern_clauses(Clause<'tcx>),
|
||||
goal_list: _intern_goals(Goal<'tcx>),
|
||||
projs: _intern_projs(ProjectionKind),
|
||||
place_elems: _intern_place_elems(PlaceElem<'tcx>)
|
||||
);
|
||||
@ -2465,14 +2431,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) }
|
||||
}
|
||||
|
||||
pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> Clauses<'tcx> {
|
||||
if ts.is_empty() { List::empty() } else { self._intern_clauses(ts) }
|
||||
}
|
||||
|
||||
pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> Goals<'tcx> {
|
||||
if ts.is_empty() { List::empty() } else { self._intern_goals(ts) }
|
||||
}
|
||||
|
||||
pub fn mk_fn_sig<I>(
|
||||
self,
|
||||
inputs: I,
|
||||
@ -2530,14 +2488,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned()))
|
||||
}
|
||||
|
||||
pub fn mk_clauses<I: InternAs<[Clause<'tcx>], Clauses<'tcx>>>(self, iter: I) -> I::Output {
|
||||
iter.intern_with(|xs| self.intern_clauses(xs))
|
||||
}
|
||||
|
||||
pub fn mk_goals<I: InternAs<[Goal<'tcx>], Goals<'tcx>>>(self, iter: I) -> I::Output {
|
||||
iter.intern_with(|xs| self.intern_goals(xs))
|
||||
}
|
||||
|
||||
/// Walks upwards from `id` to find a node which might change lint levels with attributes.
|
||||
/// It stops at `bound` and just returns it if reached.
|
||||
pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
use crate::infer::canonical::Canonical;
|
||||
use crate::mir;
|
||||
use crate::traits;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
@ -260,17 +259,6 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for traits::Environment<'tcx> {
|
||||
type CacheSelector = DefaultCacheSelector;
|
||||
|
||||
fn query_crate(&self) -> CrateNum {
|
||||
LOCAL_CRATE
|
||||
}
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for Symbol {
|
||||
type CacheSelector = DefaultCacheSelector;
|
||||
|
||||
|
@ -27,7 +27,6 @@ use crate::traits::query::{
|
||||
OutlivesBound,
|
||||
};
|
||||
use crate::traits::specialization_graph;
|
||||
use crate::traits::Clauses;
|
||||
use crate::traits::{self, Vtable};
|
||||
use crate::ty::steal::Steal;
|
||||
use crate::ty::subst::{GenericArg, SubstsRef};
|
||||
|
@ -5,7 +5,6 @@
|
||||
//! subtyping, type equality, etc.
|
||||
|
||||
use crate::mir::interpret::{get_slice_bytes, ConstValue};
|
||||
use crate::traits;
|
||||
use crate::ty::error::{ExpectedFound, TypeError};
|
||||
use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
|
||||
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
@ -786,229 +785,6 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::WhereClause<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::WhereClause<'tcx>,
|
||||
b: &traits::WhereClause<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::WhereClause<'tcx>> {
|
||||
use crate::traits::WhereClause::*;
|
||||
match (a, b) {
|
||||
(Implemented(a_pred), Implemented(b_pred)) => {
|
||||
Ok(Implemented(relation.relate(a_pred, b_pred)?))
|
||||
}
|
||||
|
||||
(ProjectionEq(a_pred), ProjectionEq(b_pred)) => {
|
||||
Ok(ProjectionEq(relation.relate(a_pred, b_pred)?))
|
||||
}
|
||||
|
||||
(RegionOutlives(a_pred), RegionOutlives(b_pred)) => {
|
||||
Ok(RegionOutlives(ty::OutlivesPredicate(
|
||||
relation.relate(&a_pred.0, &b_pred.0)?,
|
||||
relation.relate(&a_pred.1, &b_pred.1)?,
|
||||
)))
|
||||
}
|
||||
|
||||
(TypeOutlives(a_pred), TypeOutlives(b_pred)) => {
|
||||
Ok(TypeOutlives(ty::OutlivesPredicate(
|
||||
relation.relate(&a_pred.0, &b_pred.0)?,
|
||||
relation.relate(&a_pred.1, &b_pred.1)?,
|
||||
)))
|
||||
}
|
||||
|
||||
_ => Err(TypeError::Mismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::WellFormed<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::WellFormed<'tcx>,
|
||||
b: &traits::WellFormed<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::WellFormed<'tcx>> {
|
||||
use crate::traits::WellFormed::*;
|
||||
match (a, b) {
|
||||
(Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)),
|
||||
(Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)),
|
||||
_ => Err(TypeError::Mismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::FromEnv<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::FromEnv<'tcx>,
|
||||
b: &traits::FromEnv<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::FromEnv<'tcx>> {
|
||||
use crate::traits::FromEnv::*;
|
||||
match (a, b) {
|
||||
(Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)),
|
||||
(Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)),
|
||||
_ => Err(TypeError::Mismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::DomainGoal<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::DomainGoal<'tcx>,
|
||||
b: &traits::DomainGoal<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::DomainGoal<'tcx>> {
|
||||
use crate::traits::DomainGoal::*;
|
||||
match (a, b) {
|
||||
(Holds(a_wc), Holds(b_wc)) => Ok(Holds(relation.relate(a_wc, b_wc)?)),
|
||||
(WellFormed(a_wf), WellFormed(b_wf)) => Ok(WellFormed(relation.relate(a_wf, b_wf)?)),
|
||||
(FromEnv(a_fe), FromEnv(b_fe)) => Ok(FromEnv(relation.relate(a_fe, b_fe)?)),
|
||||
|
||||
(Normalize(a_pred), Normalize(b_pred)) => {
|
||||
Ok(Normalize(relation.relate(a_pred, b_pred)?))
|
||||
}
|
||||
|
||||
_ => Err(TypeError::Mismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::Goal<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::Goal<'tcx>,
|
||||
b: &traits::Goal<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::Goal<'tcx>> {
|
||||
use crate::traits::GoalKind::*;
|
||||
match (a, b) {
|
||||
(Implies(a_clauses, a_goal), Implies(b_clauses, b_goal)) => {
|
||||
let clauses = relation.relate(a_clauses, b_clauses)?;
|
||||
let goal = relation.relate(a_goal, b_goal)?;
|
||||
Ok(relation.tcx().mk_goal(Implies(clauses, goal)))
|
||||
}
|
||||
|
||||
(And(a_left, a_right), And(b_left, b_right)) => {
|
||||
let left = relation.relate(a_left, b_left)?;
|
||||
let right = relation.relate(a_right, b_right)?;
|
||||
Ok(relation.tcx().mk_goal(And(left, right)))
|
||||
}
|
||||
|
||||
(Not(a_goal), Not(b_goal)) => {
|
||||
let goal = relation.relate(a_goal, b_goal)?;
|
||||
Ok(relation.tcx().mk_goal(Not(goal)))
|
||||
}
|
||||
|
||||
(DomainGoal(a_goal), DomainGoal(b_goal)) => {
|
||||
let goal = relation.relate(a_goal, b_goal)?;
|
||||
Ok(relation.tcx().mk_goal(DomainGoal(goal)))
|
||||
}
|
||||
|
||||
(Quantified(a_qkind, a_goal), Quantified(b_qkind, b_goal)) if a_qkind == b_qkind => {
|
||||
let goal = relation.relate(a_goal, b_goal)?;
|
||||
Ok(relation.tcx().mk_goal(Quantified(*a_qkind, goal)))
|
||||
}
|
||||
|
||||
(CannotProve, CannotProve) => Ok(*a),
|
||||
|
||||
_ => Err(TypeError::Mismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::Goals<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::Goals<'tcx>,
|
||||
b: &traits::Goals<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::Goals<'tcx>> {
|
||||
if a.len() != b.len() {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
|
||||
let tcx = relation.tcx();
|
||||
let goals = a.iter().zip(b.iter()).map(|(a, b)| relation.relate(a, b));
|
||||
Ok(tcx.mk_goals(goals)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::Clause<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::Clause<'tcx>,
|
||||
b: &traits::Clause<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::Clause<'tcx>> {
|
||||
use crate::traits::Clause::*;
|
||||
match (a, b) {
|
||||
(Implies(a_clause), Implies(b_clause)) => {
|
||||
let clause = relation.relate(a_clause, b_clause)?;
|
||||
Ok(Implies(clause))
|
||||
}
|
||||
|
||||
(ForAll(a_clause), ForAll(b_clause)) => {
|
||||
let clause = relation.relate(a_clause, b_clause)?;
|
||||
Ok(ForAll(clause))
|
||||
}
|
||||
|
||||
_ => Err(TypeError::Mismatch),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::Clauses<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::Clauses<'tcx>,
|
||||
b: &traits::Clauses<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::Clauses<'tcx>> {
|
||||
if a.len() != b.len() {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
|
||||
let tcx = relation.tcx();
|
||||
let clauses = a.iter().zip(b.iter()).map(|(a, b)| relation.relate(a, b));
|
||||
Ok(tcx.mk_clauses(clauses)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::ProgramClause<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::ProgramClause<'tcx>,
|
||||
b: &traits::ProgramClause<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::ProgramClause<'tcx>> {
|
||||
Ok(traits::ProgramClause {
|
||||
goal: relation.relate(&a.goal, &b.goal)?,
|
||||
hypotheses: relation.relate(&a.hypotheses, &b.hypotheses)?,
|
||||
category: traits::ProgramClauseCategory::Other,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Relate<'tcx> for traits::Environment<'tcx> {
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::Environment<'tcx>,
|
||||
b: &traits::Environment<'tcx>,
|
||||
) -> RelateResult<'tcx, traits::Environment<'tcx>> {
|
||||
Ok(traits::Environment { clauses: relation.relate(&a.clauses, &b.clauses)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, G> Relate<'tcx> for traits::InEnvironment<'tcx, G>
|
||||
where
|
||||
G: Relate<'tcx>,
|
||||
{
|
||||
fn relate<R: TypeRelation<'tcx>>(
|
||||
relation: &mut R,
|
||||
a: &traits::InEnvironment<'tcx, G>,
|
||||
b: &traits::InEnvironment<'tcx, G>,
|
||||
) -> RelateResult<'tcx, traits::InEnvironment<'tcx, G>> {
|
||||
Ok(traits::InEnvironment {
|
||||
environment: relation.relate(&a.environment, &b.environment)?,
|
||||
goal: relation.relate(&a.goal, &b.goal)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Error handling
|
||||
|
||||
|
@ -207,38 +207,6 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
|
||||
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
|
||||
}
|
||||
|
||||
/// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked
|
||||
/// var bound at index `0`. For types, we use a `BoundVar` index equal to
|
||||
/// the type parameter index. For regions, we use the `BoundRegion::BrNamed`
|
||||
/// variant (which has a `DefId`).
|
||||
pub fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
|
||||
Self::for_item(tcx, def_id, |param, _| match param.kind {
|
||||
ty::GenericParamDefKind::Type { .. } => tcx
|
||||
.mk_ty(ty::Bound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundTy {
|
||||
var: ty::BoundVar::from(param.index),
|
||||
kind: ty::BoundTyKind::Param(param.name),
|
||||
},
|
||||
))
|
||||
.into(),
|
||||
|
||||
ty::GenericParamDefKind::Lifetime => tcx
|
||||
.mk_region(ty::RegionKind::ReLateBound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion::BrNamed(param.def_id, param.name),
|
||||
))
|
||||
.into(),
|
||||
|
||||
ty::GenericParamDefKind::Const => tcx
|
||||
.mk_const(ty::Const {
|
||||
val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
|
||||
ty: tcx.type_of(param.def_id),
|
||||
})
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a `InternalSubsts` for generic parameter definitions,
|
||||
/// by calling closures to obtain each kind.
|
||||
/// The closures get to observe the `InternalSubsts` as they're
|
||||
|
@ -4,7 +4,6 @@ use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
use rustc_trait_selection::traits::DomainGoal;
|
||||
|
||||
use crate::borrow_check::constraints::OutlivesConstraint;
|
||||
use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
|
||||
@ -100,10 +99,6 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn push_domain_goal(&mut self, _: DomainGoal<'tcx>) {
|
||||
bug!("should never be invoked with eager normalization")
|
||||
}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ extern crate rustc_middle;
|
||||
mod dropck_outlives;
|
||||
mod evaluate_obligation;
|
||||
mod implied_outlives_bounds;
|
||||
pub mod lowering;
|
||||
mod normalize_erasing_regions;
|
||||
mod normalize_projection_ty;
|
||||
mod type_op;
|
||||
@ -26,7 +25,6 @@ pub fn provide(p: &mut Providers<'_>) {
|
||||
dropck_outlives::provide(p);
|
||||
evaluate_obligation::provide(p);
|
||||
implied_outlives_bounds::provide(p);
|
||||
lowering::provide(p);
|
||||
normalize_projection_ty::provide(p);
|
||||
normalize_erasing_regions::provide(p);
|
||||
type_op::provide(p);
|
||||
|
@ -1,267 +0,0 @@
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::traits::{
|
||||
Clause, Clauses, DomainGoal, Environment, FromEnv, ProgramClause, ProgramClauseCategory,
|
||||
};
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
struct ClauseVisitor<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
round: &'a mut FxHashSet<Clause<'tcx>>,
|
||||
}
|
||||
|
||||
impl ClauseVisitor<'a, 'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>, round: &'a mut FxHashSet<Clause<'tcx>>) -> Self {
|
||||
ClauseVisitor { tcx, round }
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) {
|
||||
match ty.kind {
|
||||
ty::Projection(data) => {
|
||||
self.round.extend(
|
||||
self.tcx
|
||||
.program_clauses_for(data.item_def_id)
|
||||
.iter()
|
||||
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
|
||||
.cloned(),
|
||||
);
|
||||
}
|
||||
|
||||
ty::Dynamic(..) => {
|
||||
// FIXME: trait object rules are not yet implemented
|
||||
}
|
||||
|
||||
ty::Adt(def, ..) => {
|
||||
self.round.extend(
|
||||
self.tcx
|
||||
.program_clauses_for(def.did)
|
||||
.iter()
|
||||
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
|
||||
.cloned(),
|
||||
);
|
||||
}
|
||||
|
||||
ty::Foreign(def_id)
|
||||
| ty::FnDef(def_id, ..)
|
||||
| ty::Closure(def_id, ..)
|
||||
| ty::Generator(def_id, ..)
|
||||
| ty::Opaque(def_id, ..) => {
|
||||
self.round.extend(
|
||||
self.tcx
|
||||
.program_clauses_for(def_id)
|
||||
.iter()
|
||||
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
|
||||
.cloned(),
|
||||
);
|
||||
}
|
||||
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
| ty::Str
|
||||
| ty::Array(..)
|
||||
| ty::Slice(..)
|
||||
| ty::RawPtr(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::Tuple(..)
|
||||
| ty::Ref(..)
|
||||
| ty::Never
|
||||
| ty::Infer(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Param(..)
|
||||
| ty::Bound(..) => (),
|
||||
|
||||
ty::GeneratorWitness(..) | ty::UnnormalizedProjection(..) | ty::Error => {
|
||||
bug!("unexpected type {:?}", ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_from_env(&mut self, from_env: FromEnv<'tcx>) {
|
||||
match from_env {
|
||||
FromEnv::Trait(predicate) => {
|
||||
self.round.extend(
|
||||
self.tcx
|
||||
.program_clauses_for(predicate.def_id())
|
||||
.iter()
|
||||
.filter(|c| c.category() == ProgramClauseCategory::ImpliedBound)
|
||||
.cloned(),
|
||||
);
|
||||
}
|
||||
|
||||
FromEnv::Ty(ty) => self.visit_ty(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) {
|
||||
// The only domain goals we can find in an environment are:
|
||||
// * `DomainGoal::Holds(..)`
|
||||
// * `DomainGoal::FromEnv(..)`
|
||||
// The former do not lead to any implied bounds. So we only need
|
||||
// to visit the latter.
|
||||
if let DomainGoal::FromEnv(from_env) = domain_goal {
|
||||
self.visit_from_env(from_env);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_program_clause(&mut self, clause: ProgramClause<'tcx>) {
|
||||
self.visit_domain_goal(clause.goal);
|
||||
// No need to visit `clause.hypotheses`: they are always of the form
|
||||
// `FromEnv(...)` and were visited at a previous round.
|
||||
}
|
||||
|
||||
fn visit_clause(&mut self, clause: Clause<'tcx>) {
|
||||
match clause {
|
||||
Clause::Implies(clause) => self.visit_program_clause(clause),
|
||||
Clause::ForAll(clause) => self.visit_program_clause(*clause.skip_binder()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn program_clauses_for_env<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
environment: Environment<'tcx>,
|
||||
) -> Clauses<'tcx> {
|
||||
debug!("program_clauses_for_env(environment={:?})", environment);
|
||||
|
||||
let mut last_round = FxHashSet::default();
|
||||
{
|
||||
let mut visitor = ClauseVisitor::new(tcx, &mut last_round);
|
||||
for &clause in environment.clauses {
|
||||
visitor.visit_clause(clause);
|
||||
}
|
||||
}
|
||||
|
||||
let mut closure = last_round.clone();
|
||||
let mut next_round = FxHashSet::default();
|
||||
while !last_round.is_empty() {
|
||||
let mut visitor = ClauseVisitor::new(tcx, &mut next_round);
|
||||
for clause in last_round.drain() {
|
||||
visitor.visit_clause(clause);
|
||||
}
|
||||
last_round.extend(next_round.drain().filter(|&clause| closure.insert(clause)));
|
||||
}
|
||||
|
||||
debug!("program_clauses_for_env: closure = {:#?}", closure);
|
||||
|
||||
tcx.mk_clauses(closure.into_iter())
|
||||
}
|
||||
|
||||
crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> {
|
||||
use super::{IntoFromEnvGoal, Lower};
|
||||
use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
|
||||
|
||||
debug!("environment(def_id = {:?})", def_id);
|
||||
|
||||
// The environment of an impl Trait type is its defining function's environment.
|
||||
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
|
||||
return environment(tcx, parent);
|
||||
}
|
||||
|
||||
// Compute the bounds on `Self` and the type parameters.
|
||||
let ty::InstantiatedPredicates { predicates, .. } =
|
||||
tcx.predicates_of(def_id).instantiate_identity(tcx);
|
||||
|
||||
let clauses = predicates
|
||||
.into_iter()
|
||||
.map(|predicate| predicate.lower())
|
||||
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_from_env_goal()))
|
||||
.map(|domain_goal| domain_goal.map_bound(|bound| bound.into_program_clause()))
|
||||
// `ForAll` because each `domain_goal` is a `PolyDomainGoal` and
|
||||
// could bound lifetimes.
|
||||
.map(Clause::ForAll);
|
||||
|
||||
let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
|
||||
let node = tcx.hir().get(hir_id);
|
||||
|
||||
enum NodeKind {
|
||||
TraitImpl,
|
||||
InherentImpl,
|
||||
Fn,
|
||||
Other,
|
||||
};
|
||||
|
||||
let node_kind = match node {
|
||||
Node::TraitItem(item) => match item.kind {
|
||||
TraitItemKind::Fn(..) => NodeKind::Fn,
|
||||
_ => NodeKind::Other,
|
||||
},
|
||||
|
||||
Node::ImplItem(item) => match item.kind {
|
||||
ImplItemKind::Fn(..) => NodeKind::Fn,
|
||||
_ => NodeKind::Other,
|
||||
},
|
||||
|
||||
Node::Item(item) => match item.kind {
|
||||
ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl,
|
||||
ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl,
|
||||
ItemKind::Fn(..) => NodeKind::Fn,
|
||||
_ => NodeKind::Other,
|
||||
},
|
||||
|
||||
Node::ForeignItem(item) => match item.kind {
|
||||
ForeignItemKind::Fn(..) => NodeKind::Fn,
|
||||
_ => NodeKind::Other,
|
||||
},
|
||||
|
||||
// FIXME: closures?
|
||||
_ => NodeKind::Other,
|
||||
};
|
||||
|
||||
// FIXME(eddyb) isn't the unordered nature of this a hazard?
|
||||
let mut inputs = FxHashSet::default();
|
||||
|
||||
match node_kind {
|
||||
// In a trait impl, we assume that the header trait ref and all its
|
||||
// constituents are well-formed.
|
||||
NodeKind::TraitImpl => {
|
||||
let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
|
||||
|
||||
inputs.extend(trait_ref.substs.iter().flat_map(|&arg| arg.walk()));
|
||||
}
|
||||
|
||||
// In an inherent impl, we assume that the receiver type and all its
|
||||
// constituents are well-formed.
|
||||
NodeKind::InherentImpl => {
|
||||
let self_ty = tcx.type_of(def_id);
|
||||
inputs.extend(self_ty.walk());
|
||||
}
|
||||
|
||||
// In an fn, we assume that the arguments and all their constituents are
|
||||
// well-formed.
|
||||
NodeKind::Fn => {
|
||||
let fn_sig = tcx.fn_sig(def_id);
|
||||
let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig);
|
||||
|
||||
inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
|
||||
}
|
||||
|
||||
NodeKind::Other => (),
|
||||
}
|
||||
|
||||
let clauses = clauses.chain(
|
||||
inputs
|
||||
.into_iter()
|
||||
.filter_map(|arg| {
|
||||
match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => Some(FromEnv::Ty(ty)),
|
||||
|
||||
// FIXME(eddyb) no WF conditions from lifetimes?
|
||||
GenericArgKind::Lifetime(_) => None,
|
||||
|
||||
// FIXME(eddyb) support const generics in Chalk
|
||||
GenericArgKind::Const(_) => None,
|
||||
}
|
||||
})
|
||||
.map(DomainGoal::FromEnv)
|
||||
.map(|domain_goal| domain_goal.into_program_clause())
|
||||
.map(Clause::Implies),
|
||||
);
|
||||
|
||||
debug!("environment: clauses = {:?}", clauses);
|
||||
|
||||
Environment { clauses: tcx.mk_clauses(clauses) }
|
||||
}
|
@ -1,627 +0,0 @@
|
||||
mod environment;
|
||||
|
||||
use rustc_ast::ast;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::traits::{
|
||||
Clause, Clauses, DomainGoal, FromEnv, GoalKind, PolyDomainGoal, ProgramClause,
|
||||
ProgramClauseCategory, WellFormed, WhereClause,
|
||||
};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{self, List, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use std::iter;
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
*p = Providers {
|
||||
program_clauses_for,
|
||||
program_clauses_for_env: environment::program_clauses_for_env,
|
||||
environment: environment::environment,
|
||||
..*p
|
||||
};
|
||||
}
|
||||
|
||||
crate trait Lower<T> {
|
||||
/// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk-like type.
|
||||
fn lower(&self) -> T;
|
||||
}
|
||||
|
||||
impl<T, U> Lower<Vec<U>> for Vec<T>
|
||||
where
|
||||
T: Lower<U>,
|
||||
{
|
||||
fn lower(&self) -> Vec<U> {
|
||||
self.iter().map(|item| item.lower()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Lower<WhereClause<'tcx>> for ty::TraitPredicate<'tcx> {
|
||||
fn lower(&self) -> WhereClause<'tcx> {
|
||||
WhereClause::Implemented(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Lower<WhereClause<'tcx>> for ty::ProjectionPredicate<'tcx> {
|
||||
fn lower(&self) -> WhereClause<'tcx> {
|
||||
WhereClause::ProjectionEq(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Lower<WhereClause<'tcx>> for ty::RegionOutlivesPredicate<'tcx> {
|
||||
fn lower(&self) -> WhereClause<'tcx> {
|
||||
WhereClause::RegionOutlives(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Lower<WhereClause<'tcx>> for ty::TypeOutlivesPredicate<'tcx> {
|
||||
fn lower(&self) -> WhereClause<'tcx> {
|
||||
WhereClause::TypeOutlives(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> Lower<DomainGoal<'tcx>> for T
|
||||
where
|
||||
T: Lower<WhereClause<'tcx>>,
|
||||
{
|
||||
fn lower(&self) -> DomainGoal<'tcx> {
|
||||
DomainGoal::Holds(self.lower())
|
||||
}
|
||||
}
|
||||
|
||||
/// `ty::Binder` is used for wrapping a rustc construction possibly containing generic
|
||||
/// lifetimes, e.g., `for<'a> T: Fn(&'a i32)`. Instead of representing higher-ranked things
|
||||
/// in that leaf-form (i.e., `Holds(Implemented(Binder<TraitPredicate>))` in the previous
|
||||
/// example), we model them with quantified domain goals, e.g., as for the previous example:
|
||||
/// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like
|
||||
/// `Binder<Holds(Implemented(TraitPredicate))>`.
|
||||
impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T>
|
||||
where
|
||||
T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>,
|
||||
{
|
||||
fn lower(&self) -> PolyDomainGoal<'tcx> {
|
||||
self.map_bound_ref(|p| p.lower())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
|
||||
fn lower(&self) -> PolyDomainGoal<'tcx> {
|
||||
use rustc_middle::ty::Predicate;
|
||||
|
||||
match self {
|
||||
Predicate::Trait(predicate, _) => predicate.lower(),
|
||||
Predicate::RegionOutlives(predicate) => predicate.lower(),
|
||||
Predicate::TypeOutlives(predicate) => predicate.lower(),
|
||||
Predicate::Projection(predicate) => predicate.lower(),
|
||||
|
||||
Predicate::WellFormed(..)
|
||||
| Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::Subtype(..)
|
||||
| Predicate::ConstEvaluatable(..) => bug!("unexpected predicate {}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for implied bounds related rules (see rustc dev guide).
|
||||
trait IntoFromEnvGoal {
|
||||
/// Transforms an existing goal into a `FromEnv` goal.
|
||||
fn into_from_env_goal(self) -> Self;
|
||||
}
|
||||
|
||||
/// Used for well-formedness related rules (see rustc dev guide).
|
||||
trait IntoWellFormedGoal {
|
||||
/// Transforms an existing goal into a `WellFormed` goal.
|
||||
fn into_well_formed_goal(self) -> Self;
|
||||
}
|
||||
|
||||
impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
|
||||
fn into_from_env_goal(self) -> DomainGoal<'tcx> {
|
||||
use self::WhereClause::*;
|
||||
|
||||
match self {
|
||||
DomainGoal::Holds(Implemented(trait_ref)) => {
|
||||
DomainGoal::FromEnv(FromEnv::Trait(trait_ref))
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> IntoWellFormedGoal for DomainGoal<'tcx> {
|
||||
fn into_well_formed_goal(self) -> DomainGoal<'tcx> {
|
||||
use self::WhereClause::*;
|
||||
|
||||
match self {
|
||||
DomainGoal::Holds(Implemented(trait_ref)) => {
|
||||
DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn program_clauses_for(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
|
||||
// FIXME(eddyb) this should only be using `def_kind`.
|
||||
match tcx.def_key(def_id).disambiguated_data.data {
|
||||
DefPathData::TypeNs(..) => match tcx.def_kind(def_id) {
|
||||
DefKind::Trait | DefKind::TraitAlias => program_clauses_for_trait(tcx, def_id),
|
||||
// FIXME(eddyb) deduplicate this `associated_item` call with
|
||||
// `program_clauses_for_associated_type_{value,def}`.
|
||||
DefKind::AssocTy => match tcx.associated_item(def_id).container {
|
||||
ty::AssocItemContainer::ImplContainer(_) => {
|
||||
program_clauses_for_associated_type_value(tcx, def_id)
|
||||
}
|
||||
ty::AssocItemContainer::TraitContainer(_) => {
|
||||
program_clauses_for_associated_type_def(tcx, def_id)
|
||||
}
|
||||
},
|
||||
DefKind::Struct
|
||||
| DefKind::Enum
|
||||
| DefKind::TyAlias
|
||||
| DefKind::Union
|
||||
| DefKind::OpaqueTy => program_clauses_for_type_def(tcx, def_id),
|
||||
_ => List::empty(),
|
||||
},
|
||||
DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
|
||||
_ => List::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
fn program_clauses_for_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
|
||||
// `trait Trait<P1..Pn> where WC { .. } // P0 == Self`
|
||||
|
||||
// Rule Implemented-From-Env (see rustc dev guide)
|
||||
//
|
||||
// ```
|
||||
// forall<Self, P1..Pn> {
|
||||
// Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
|
||||
// }
|
||||
// ```
|
||||
|
||||
let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
|
||||
|
||||
// `Self: Trait<P1..Pn>`
|
||||
let trait_pred = ty::TraitPredicate { trait_ref: ty::TraitRef { def_id, substs: bound_vars } };
|
||||
|
||||
// `Implemented(Self: Trait<P1..Pn>)`
|
||||
let impl_trait: DomainGoal<'_> = trait_pred.lower();
|
||||
|
||||
// `FromEnv(Self: Trait<P1..Pn>)`
|
||||
let from_env_goal = tcx.mk_goal(impl_trait.into_from_env_goal().into_goal());
|
||||
let hypotheses = tcx.intern_goals(&[from_env_goal]);
|
||||
|
||||
// `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)`
|
||||
let implemented_from_env = ProgramClause {
|
||||
goal: impl_trait,
|
||||
hypotheses,
|
||||
category: ProgramClauseCategory::ImpliedBound,
|
||||
};
|
||||
|
||||
let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env));
|
||||
|
||||
let predicates = tcx.predicates_defined_on(def_id).predicates;
|
||||
|
||||
// Warning: these where clauses are not substituted for bound vars yet,
|
||||
// so that we don't need to adjust binders in the `FromEnv` rules below
|
||||
// (see the FIXME).
|
||||
let where_clauses = &predicates.iter().map(|(wc, _)| wc.lower()).collect::<Vec<_>>();
|
||||
|
||||
// Rule Implied-Bound-From-Trait
|
||||
//
|
||||
// For each where clause WC:
|
||||
// ```
|
||||
// forall<Self, P1..Pn> {
|
||||
// FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn)
|
||||
// }
|
||||
// ```
|
||||
|
||||
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
|
||||
let implied_bound_clauses = where_clauses
|
||||
.iter()
|
||||
.cloned()
|
||||
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`
|
||||
.map(|wc| {
|
||||
// we move binders to the left
|
||||
wc.map_bound(|goal| ProgramClause {
|
||||
// FIXME: As where clauses can only bind lifetimes for now, and that named
|
||||
// bound regions have a def-id, it is safe to just inject `bound_vars` and
|
||||
// `hypotheses` (which contain named vars bound at index `0`) into this
|
||||
// binding level. This may change if we ever allow where clauses to bind
|
||||
// types (e.g. for GATs things), because bound types only use a `BoundVar`
|
||||
// index (no def-id).
|
||||
goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
|
||||
hypotheses,
|
||||
|
||||
category: ProgramClauseCategory::ImpliedBound,
|
||||
})
|
||||
})
|
||||
.map(Clause::ForAll);
|
||||
|
||||
// Rule WellFormed-TraitRef
|
||||
//
|
||||
// Here `WC` denotes the set of all where clauses:
|
||||
// ```
|
||||
// forall<Self, P1..Pn> {
|
||||
// WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
|
||||
// }
|
||||
// ```
|
||||
|
||||
// `WellFormed(WC)`
|
||||
let wf_conditions = where_clauses
|
||||
.iter()
|
||||
.map(|wc| wc.subst(tcx, bound_vars))
|
||||
.map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()));
|
||||
|
||||
// `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
|
||||
hypotheses: tcx.mk_goals(
|
||||
iter::once(tcx.mk_goal(GoalKind::DomainGoal(impl_trait))).chain(
|
||||
wf_conditions.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
|
||||
),
|
||||
),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
tcx.mk_clauses(
|
||||
iter::once(implemented_from_env).chain(implied_bound_clauses).chain(iter::once(wf_clause)),
|
||||
)
|
||||
}
|
||||
|
||||
fn program_clauses_for_impl(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> {
|
||||
if let ty::ImplPolarity::Negative = tcx.impl_polarity(def_id) {
|
||||
return List::empty();
|
||||
}
|
||||
|
||||
// Rule Implemented-From-Impl (see rustc dev guide)
|
||||
//
|
||||
// `impl<P0..Pn> Trait<A1..An> for A0 where WC { .. }`
|
||||
//
|
||||
// ```
|
||||
// forall<P0..Pn> {
|
||||
// Implemented(A0: Trait<A1..An>) :- WC
|
||||
// }
|
||||
// ```
|
||||
|
||||
let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
|
||||
|
||||
let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl").subst(tcx, bound_vars);
|
||||
|
||||
// `Implemented(A0: Trait<A1..An>)`
|
||||
let trait_pred = ty::TraitPredicate { trait_ref }.lower();
|
||||
|
||||
// `WC`
|
||||
let predicates = tcx.predicates_of(def_id).predicates;
|
||||
let where_clauses =
|
||||
predicates.iter().map(|(wc, _)| wc.lower()).map(|wc| wc.subst(tcx, bound_vars));
|
||||
|
||||
// `Implemented(A0: Trait<A1..An>) :- WC`
|
||||
let clause = ProgramClause {
|
||||
goal: trait_pred,
|
||||
hypotheses: tcx.mk_goals(
|
||||
where_clauses.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
|
||||
),
|
||||
category: ProgramClauseCategory::Other,
|
||||
};
|
||||
tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::bind(clause))))
|
||||
}
|
||||
|
||||
pub fn program_clauses_for_type_def(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> {
|
||||
// Rule WellFormed-Type
|
||||
//
|
||||
// `struct Ty<P1..Pn> where WC1, ..., WCm`
|
||||
//
|
||||
// ```
|
||||
// forall<P1..Pn> {
|
||||
// WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)`
|
||||
// }
|
||||
// ```
|
||||
|
||||
let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id);
|
||||
|
||||
// `Ty<...>`
|
||||
let ty = tcx.type_of(def_id).subst(tcx, bound_vars);
|
||||
|
||||
// Warning: these where clauses are not substituted for bound vars yet,
|
||||
// so that we don't need to adjust binders in the `FromEnv` rules below
|
||||
// (see the FIXME).
|
||||
let where_clauses =
|
||||
tcx.predicates_of(def_id).predicates.iter().map(|(wc, _)| wc.lower()).collect::<Vec<_>>();
|
||||
|
||||
// `WellFormed(Ty<...>) :- WellFormed(WC1), ..., WellFormed(WCm)`
|
||||
let well_formed_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
|
||||
hypotheses: tcx.mk_goals(
|
||||
where_clauses
|
||||
.iter()
|
||||
.map(|wc| wc.subst(tcx, bound_vars))
|
||||
.map(|wc| wc.map_bound(|bound| bound.into_well_formed_goal()))
|
||||
.map(|wc| tcx.mk_goal(GoalKind::from_poly_domain_goal(wc, tcx))),
|
||||
),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let well_formed_clause = Clause::ForAll(ty::Binder::bind(well_formed_clause));
|
||||
|
||||
// Rule Implied-Bound-From-Type
|
||||
//
|
||||
// For each where clause `WC`:
|
||||
// ```
|
||||
// forall<P1..Pn> {
|
||||
// FromEnv(WC) :- FromEnv(Ty<...>)
|
||||
// }
|
||||
// ```
|
||||
|
||||
// `FromEnv(Ty<...>)`
|
||||
let from_env_goal = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(ty)).into_goal());
|
||||
let hypotheses = tcx.intern_goals(&[from_env_goal]);
|
||||
|
||||
// For each where clause `WC`:
|
||||
let from_env_clauses = where_clauses
|
||||
.into_iter()
|
||||
// `FromEnv(WC) :- FromEnv(Ty<...>)`
|
||||
.map(|wc| {
|
||||
// move the binders to the left
|
||||
wc.map_bound(|goal| ProgramClause {
|
||||
// FIXME: we inject `bound_vars` and `hypotheses` into this binding
|
||||
// level, which may be incorrect in the future: see the FIXME in
|
||||
// `program_clauses_for_trait`.
|
||||
goal: goal.subst(tcx, bound_vars).into_from_env_goal(),
|
||||
hypotheses,
|
||||
|
||||
category: ProgramClauseCategory::ImpliedBound,
|
||||
})
|
||||
})
|
||||
.map(Clause::ForAll);
|
||||
|
||||
tcx.mk_clauses(iter::once(well_formed_clause).chain(from_env_clauses))
|
||||
}
|
||||
|
||||
pub fn program_clauses_for_associated_type_def(tcx: TyCtxt<'_>, item_id: DefId) -> Clauses<'_> {
|
||||
// Rule ProjectionEq-Placeholder
|
||||
//
|
||||
// ```
|
||||
// trait Trait<P1..Pn> {
|
||||
// type AssocType<Pn+1..Pm>;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// `ProjectionEq` can succeed by skolemizing, see "associated type"
|
||||
// chapter for more:
|
||||
// ```
|
||||
// forall<Self, P1..Pn, Pn+1..Pm> {
|
||||
// ProjectionEq(
|
||||
// <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
|
||||
// (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
|
||||
// )
|
||||
// }
|
||||
// ```
|
||||
|
||||
let item = tcx.associated_item(item_id);
|
||||
debug_assert_eq!(item.kind, ty::AssocKind::Type);
|
||||
let trait_id = match item.container {
|
||||
ty::AssocItemContainer::TraitContainer(trait_id) => trait_id,
|
||||
_ => bug!("not an trait container"),
|
||||
};
|
||||
|
||||
let trait_bound_vars = InternalSubsts::bound_vars_for_item(tcx, trait_id);
|
||||
let trait_ref = ty::TraitRef { def_id: trait_id, substs: trait_bound_vars };
|
||||
|
||||
let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
|
||||
let placeholder_ty = tcx.mk_ty(ty::UnnormalizedProjection(projection_ty));
|
||||
let projection_eq =
|
||||
WhereClause::ProjectionEq(ty::ProjectionPredicate { projection_ty, ty: placeholder_ty });
|
||||
|
||||
let projection_eq_clause = ProgramClause {
|
||||
goal: DomainGoal::Holds(projection_eq),
|
||||
hypotheses: ty::List::empty(),
|
||||
category: ProgramClauseCategory::Other,
|
||||
};
|
||||
let projection_eq_clause = Clause::ForAll(ty::Binder::bind(projection_eq_clause));
|
||||
|
||||
// Rule WellFormed-AssocTy
|
||||
// ```
|
||||
// forall<Self, P1..Pn, Pn+1..Pm> {
|
||||
// WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
|
||||
// :- WellFormed(Self: Trait<P1..Pn>)
|
||||
// }
|
||||
// ```
|
||||
|
||||
let trait_predicate = ty::TraitPredicate { trait_ref };
|
||||
let hypothesis =
|
||||
tcx.mk_goal(DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)).into_goal());
|
||||
|
||||
let wf_clause = ProgramClause {
|
||||
goal: DomainGoal::WellFormed(WellFormed::Ty(placeholder_ty)),
|
||||
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
|
||||
category: ProgramClauseCategory::WellFormed,
|
||||
};
|
||||
let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause));
|
||||
|
||||
// Rule Implied-Trait-From-AssocTy
|
||||
// ```
|
||||
// forall<Self, P1..Pn, Pn+1..Pm> {
|
||||
// FromEnv(Self: Trait<P1..Pn>)
|
||||
// :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
|
||||
// }
|
||||
// ```
|
||||
|
||||
let hypothesis = tcx.mk_goal(DomainGoal::FromEnv(FromEnv::Ty(placeholder_ty)).into_goal());
|
||||
|
||||
let from_env_clause = ProgramClause {
|
||||
goal: DomainGoal::FromEnv(FromEnv::Trait(trait_predicate)),
|
||||
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
|
||||
category: ProgramClauseCategory::ImpliedBound,
|
||||
};
|
||||
let from_env_clause = Clause::ForAll(ty::Binder::bind(from_env_clause));
|
||||
|
||||
// Rule ProjectionEq-Normalize
|
||||
//
|
||||
// ProjectionEq can succeed by normalizing:
|
||||
// ```
|
||||
// forall<Self, P1..Pn, Pn+1..Pm, U> {
|
||||
// ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
|
||||
// Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
|
||||
// }
|
||||
// ```
|
||||
|
||||
let offset = tcx.generics_of(trait_id).params.iter().map(|p| p.index).max().unwrap_or(0);
|
||||
// Add a new type param after the existing ones (`U` in the comment above).
|
||||
let ty_var = ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(offset + 1).into());
|
||||
|
||||
// `ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U)`
|
||||
let projection = ty::ProjectionPredicate { projection_ty, ty: tcx.mk_ty(ty_var) };
|
||||
|
||||
// `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> U)`
|
||||
let hypothesis = tcx.mk_goal(DomainGoal::Normalize(projection).into_goal());
|
||||
|
||||
// ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
|
||||
// Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
|
||||
let normalize_clause = ProgramClause {
|
||||
goal: DomainGoal::Holds(WhereClause::ProjectionEq(projection)),
|
||||
hypotheses: tcx.mk_goals(iter::once(hypothesis)),
|
||||
category: ProgramClauseCategory::Other,
|
||||
};
|
||||
let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
|
||||
|
||||
let clauses = iter::once(projection_eq_clause)
|
||||
.chain(iter::once(wf_clause))
|
||||
.chain(iter::once(from_env_clause))
|
||||
.chain(iter::once(normalize_clause));
|
||||
|
||||
tcx.mk_clauses(clauses)
|
||||
}
|
||||
|
||||
pub fn program_clauses_for_associated_type_value(tcx: TyCtxt<'_>, item_id: DefId) -> Clauses<'_> {
|
||||
// Rule Normalize-From-Impl (see rustc dev guide)
|
||||
//
|
||||
// ```
|
||||
// impl<P0..Pn> Trait<A1..An> for A0 {
|
||||
// type AssocType<Pn+1..Pm> = T;
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// FIXME: For the moment, we don't account for where clauses written on the associated
|
||||
// ty definition (i.e., in the trait def, as in `type AssocType<T> where T: Sized`).
|
||||
// ```
|
||||
// forall<P0..Pm> {
|
||||
// forall<Pn+1..Pm> {
|
||||
// Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
|
||||
// Implemented(A0: Trait<A1..An>)
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
|
||||
let item = tcx.associated_item(item_id);
|
||||
debug_assert_eq!(item.kind, ty::AssocKind::Type);
|
||||
let impl_id = match item.container {
|
||||
ty::AssocItemContainer::ImplContainer(impl_id) => impl_id,
|
||||
_ => bug!("not an impl container"),
|
||||
};
|
||||
|
||||
let impl_bound_vars = InternalSubsts::bound_vars_for_item(tcx, impl_id);
|
||||
|
||||
// `A0 as Trait<A1..An>`
|
||||
let trait_ref = tcx.impl_trait_ref(impl_id).unwrap().subst(tcx, impl_bound_vars);
|
||||
|
||||
// `T`
|
||||
let ty = tcx.type_of(item_id);
|
||||
|
||||
// `Implemented(A0: Trait<A1..An>)`
|
||||
let trait_implemented: DomainGoal<'_> = ty::TraitPredicate { trait_ref }.lower();
|
||||
|
||||
// `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
|
||||
let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident);
|
||||
|
||||
// `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
|
||||
let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
|
||||
|
||||
// `Normalize(... -> T) :- ...`
|
||||
let normalize_clause = ProgramClause {
|
||||
goal: normalize_goal,
|
||||
hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(GoalKind::DomainGoal(trait_implemented)))),
|
||||
category: ProgramClauseCategory::Other,
|
||||
};
|
||||
let normalize_clause = Clause::ForAll(ty::Binder::bind(normalize_clause));
|
||||
|
||||
tcx.mk_clauses(iter::once(normalize_clause))
|
||||
}
|
||||
|
||||
pub fn dump_program_clauses(tcx: TyCtxt<'_>) {
|
||||
if !tcx.features().rustc_attrs {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut visitor = ClauseDumper { tcx };
|
||||
tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
|
||||
}
|
||||
|
||||
struct ClauseDumper<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl ClauseDumper<'tcx> {
|
||||
fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) {
|
||||
let def_id = self.tcx.hir().local_def_id(hir_id);
|
||||
for attr in attrs {
|
||||
let mut clauses = None;
|
||||
|
||||
if attr.check_name(sym::rustc_dump_program_clauses) {
|
||||
clauses = Some(self.tcx.program_clauses_for(def_id));
|
||||
}
|
||||
|
||||
if attr.check_name(sym::rustc_dump_env_program_clauses) {
|
||||
let environment = self.tcx.environment(def_id);
|
||||
clauses = Some(self.tcx.program_clauses_for_env(environment));
|
||||
}
|
||||
|
||||
if let Some(clauses) = clauses {
|
||||
let mut err = self.tcx.sess.struct_span_err(attr.span, "program clause dump");
|
||||
|
||||
let mut strings: Vec<_> = clauses.iter().map(|clause| clause.to_string()).collect();
|
||||
|
||||
strings.sort();
|
||||
|
||||
for string in strings {
|
||||
err.note(&string);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for ClauseDumper<'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::OnlyBodies(self.tcx.hir())
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
self.process_attrs(item.hir_id, &item.attrs);
|
||||
intravisit::walk_item(self, item);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
|
||||
self.process_attrs(trait_item.hir_id, &trait_item.attrs);
|
||||
intravisit::walk_trait_item(self, trait_item);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
||||
self.process_attrs(impl_item.hir_id, &impl_item.attrs);
|
||||
intravisit::walk_impl_item(self, impl_item);
|
||||
}
|
||||
|
||||
fn visit_struct_field(&mut self, s: &'tcx hir::StructField<'tcx>) {
|
||||
self.process_attrs(s.hir_id, &s.attrs);
|
||||
intravisit::walk_struct_field(self, s);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user