| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::TypeOutlives(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => None,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
Some(OutlivesBound::RegionSubRegion(r_b, r_a))
}
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateObligation<'_>, 40);
+static_assert_size!(PredicateObligation<'_>, 32);
pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
.map(|predicate| predicate_obligation(predicate, None)),
);
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ // Nothing to elaborate
+ }
}
}
}
ClosureKind(..) |
Subtype(..) |
ConstEvaluatable(..) |
- ConstEquate(..) => continue,
+ ConstEquate(..) |
+ TypeWellFormedFromEnv(..) => continue,
};
if predicate.is_global() {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
}
query evaluate_goal(
- goal: traits::ChalkCanonicalGoal<'tcx>
+ goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution
//! interned Chalk types.
use rustc_middle::mir::interpret::ConstValue;
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtDef, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_target::spec::abi::Abi;
-use smallvec::SmallVec;
-
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
type Interner = Self;
}
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
-pub enum ChalkEnvironmentClause<'tcx> {
- /// A normal rust `ty::Predicate` in the environment.
- Predicate(ty::Predicate<'tcx>),
- /// A special clause in the environment that gets lowered to
- /// `chalk_ir::FromEnv::Ty`.
- TypeFromEnv(Ty<'tcx>),
-}
-
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ChalkEnvironmentClause<'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_chalk_environment_clause_list(&v)
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.iter().any(|t| t.visit_with(visitor))
- }
-}
-/// We have to elaborate the environment of a chalk goal *before*
-/// canonicalization. This type wraps the predicate and the elaborated
-/// environment.
+/// A chalk environment and goal.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub struct ChalkEnvironmentAndGoal<'tcx> {
- pub environment: &'tcx ty::List<ChalkEnvironmentClause<'tcx>>,
+ pub environment: &'tcx ty::List<ty::Predicate<'tcx>>,
pub goal: ty::Predicate<'tcx>,
}
pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
-pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>;
+pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>;
pub use self::ImplSource::*;
pub use self::ObligationCauseCode::*;
-pub use self::chalk::{
- ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustInterner as ChalkRustInterner,
-};
+pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner};
/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, Const<'tcx>>,
-
- chalk_environment_clause_list: InternedSet<'tcx, List<traits::ChalkEnvironmentClause<'tcx>>>,
}
impl<'tcx> CtxtInterners<'tcx> {
projs: Default::default(),
place_elems: Default::default(),
const_: Default::default(),
- chalk_environment_clause_list: Default::default(),
}
}
}
macro_rules! slice_interners {
- ($($field:ident: $method:ident($ty:ty)),+) => (
+ ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => (
$(impl<'tcx> TyCtxt<'tcx> {
pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
self.interners.$field.intern_ref(v, || {
predicates: _intern_predicates(Predicate<'tcx>),
projs: _intern_projs(ProjectionKind),
place_elems: _intern_place_elems(PlaceElem<'tcx>),
- chalk_environment_clause_list:
- _intern_chalk_environment_clause_list(traits::ChalkEnvironmentClause<'tcx>)
);
impl<'tcx> TyCtxt<'tcx> {
if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) }
}
- pub fn intern_chalk_environment_clause_list(
- self,
- ts: &[traits::ChalkEnvironmentClause<'tcx>],
- ) -> &'tcx List<traits::ChalkEnvironmentClause<'tcx>> {
- if ts.is_empty() { List::empty() } else { self._intern_chalk_environment_clause_list(ts) }
- }
-
pub fn mk_fn_sig<I>(
self,
inputs: I,
self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned()))
}
- pub fn mk_chalk_environment_clause_list<
- I: InternAs<
- [traits::ChalkEnvironmentClause<'tcx>],
- &'tcx List<traits::ChalkEnvironmentClause<'tcx>>,
- >,
- >(
- self,
- iter: I,
- ) -> I::Output {
- iter.intern_with(|xs| self.intern_chalk_environment_clause_list(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 {
self.add_const(expected);
self.add_const(found);
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ self.add_ty(ty);
+ }
}
}
/// Constants must be equal. The first component is the const that is expected.
ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
+
+ /// Represents a type found in the environment that we can use for implied bounds.
+ ///
+ /// Only used for Chalk.
+ TypeWellFormedFromEnv(Ty<'tcx>),
}
impl<'tcx> PredicateAtom<'tcx> {
| PredicateAtom::ClosureKind(..)
| PredicateAtom::TypeOutlives(..)
| PredicateAtom::ConstEvaluatable(..)
- | PredicateAtom::ConstEquate(..) => None,
+ | PredicateAtom::ConstEquate(..)
+ | PredicateAtom::TypeWellFormedFromEnv(..) => None,
}
}
| PredicateAtom::ObjectSafe(..)
| PredicateAtom::ClosureKind(..)
| PredicateAtom::ConstEvaluatable(..)
- | PredicateAtom::ConstEquate(..) => None,
+ | PredicateAtom::ConstEquate(..)
+ | PredicateAtom::TypeWellFormedFromEnv(..) => None,
}
}
}
///
/// Note: This is packed, use the reveal() method to access it.
packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, traits::Reveal, true>,
-
- /// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
- /// register that `def_id` (useful for transitioning to the chalk trait
- /// solver).
- pub def_id: Option<DefId>,
}
unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
f.debug_struct("ParamEnv")
.field("caller_bounds", &self.caller_bounds())
.field("reveal", &self.reveal())
- .field("def_id", &self.def_id)
.finish()
}
}
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.caller_bounds().hash_stable(hcx, hasher);
self.reveal().hash_stable(hcx, hasher);
- self.def_id.hash_stable(hcx, hasher);
}
}
impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
- ParamEnv::new(
- self.caller_bounds().fold_with(folder),
- self.reveal().fold_with(folder),
- self.def_id.fold_with(folder),
- )
+ ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.caller_bounds().visit_with(visitor)
- || self.reveal().visit_with(visitor)
- || self.def_id.visit_with(visitor)
+ self.caller_bounds().visit_with(visitor) || self.reveal().visit_with(visitor)
}
}
/// type-checking.
#[inline]
pub fn empty() -> Self {
- Self::new(List::empty(), Reveal::UserFacing, None)
+ Self::new(List::empty(), Reveal::UserFacing)
}
#[inline]
/// or invoke `param_env.with_reveal_all()`.
#[inline]
pub fn reveal_all() -> Self {
- Self::new(List::empty(), Reveal::All, None)
+ Self::new(List::empty(), Reveal::All)
}
/// Construct a trait environment with the given set of predicates.
#[inline]
- pub fn new(
- caller_bounds: &'tcx List<Predicate<'tcx>>,
- reveal: Reveal,
- def_id: Option<DefId>,
- ) -> Self {
- ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), def_id }
+ pub fn new(caller_bounds: &'tcx List<Predicate<'tcx>>, reveal: Reveal) -> Self {
+ ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) }
}
pub fn with_user_facing(mut self) -> Self {
return self;
}
- ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id)
+ ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All)
}
/// Returns this same environment but with no caller bounds.
pub fn without_caller_bounds(self) -> Self {
- Self::new(List::empty(), self.reveal(), self.def_id)
+ Self::new(List::empty(), self.reveal())
}
/// Creates a suitable environment in which to perform trait
print(c2),
write("`"))
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ p!(write("the type `"),
+ print(ty),
+ write("` is found in the environment"))
+ }
}
}
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
}
ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+ ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ write!(f, "TypeWellFormedFromEnv({:?})", ty)
+ }
}
}
}
ty::PredicateAtom::ConstEquate(c1, c2) => {
tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2))
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ tcx.lift(&ty).map(ty::PredicateAtom::TypeWellFormedFromEnv)
+ }
}
}
}
type Lifted = ty::ParamEnv<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.caller_bounds())
- .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id))
+ .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
}
}
| ty::PredicateAtom::WellFormed(_)
| ty::PredicateAtom::Projection(_)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => continue,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
ty::PredicateAtom::ObjectSafe(_) => {
bug!("object safe predicate on function: {:#?}", predicate)
}
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::RegionOutlives(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => None,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
// Search for a bound of the form `erased_self_ty
// : 'a`, but be wary of something like `for<'a>
computed_preds.clone().chain(user_computed_preds.iter().cloned()),
)
.map(|o| o.predicate);
- new_env =
- ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None);
+ new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal());
}
let final_user_env = ty::ParamEnv::new(
tcx.mk_predicates(user_computed_preds.into_iter()),
user_env.reveal(),
- None,
);
debug!(
"evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
use crate::infer::InferCtxt;
use crate::traits::query::NoSolution;
use crate::traits::{
- ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode,
- ObligationCause, PredicateObligation, SelectionError, TraitEngine,
+ ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause,
+ PredicateObligation, SelectionError, TraitEngine,
};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty};
pub struct FulfillmentContext<'tcx> {
obligations: FxIndexSet<PredicateObligation<'tcx>>,
}
}
-fn environment<'tcx>(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
-) -> &'tcx ty::List<ChalkEnvironmentClause<'tcx>> {
- use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
- use rustc_middle::ty::subst::GenericArgKind;
-
- 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(ChalkEnvironmentClause::Predicate);
-
- let hir_id = tcx.hir().local_def_id_to_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 = FxIndexSet::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");
-
- // FIXME(chalk): this has problems because of late-bound regions
- //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
- inputs.extend(trait_ref.substs.iter());
- }
-
- // 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 input_clauses = inputs.into_iter().filter_map(|arg| {
- match arg.unpack() {
- GenericArgKind::Type(ty) => Some(ChalkEnvironmentClause::TypeFromEnv(ty)),
-
- // FIXME(eddyb) no WF conditions from lifetimes?
- GenericArgKind::Lifetime(_) => None,
-
- // FIXME(eddyb) support const generics in Chalk
- GenericArgKind::Const(_) => None,
- }
- });
-
- tcx.mk_chalk_environment_clause_list(clauses.chain(input_clauses))
-}
-
-/// We need to wrap a `ty::Predicate` in an elaborated environment *before* we
-/// canonicalize. This is due to the fact that we insert extra clauses into the
-/// environment for all input types (`FromEnv`).
-fn in_environment(
- infcx: &InferCtxt<'_, 'tcx>,
- obligation: &PredicateObligation<'tcx>,
-) -> ChalkEnvironmentAndGoal<'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) => environment(infcx.tcx, def_id),
- None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(),
- // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl
- // and ui/generics/generic-static-methods
- //_ => bug!("non-empty `ParamEnv` with no def-id"),
- _ => ty::List::empty(),
- };
-
- ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }
-}
-
impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn normalize_projection_type(
&mut self,
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ assert!(!infcx.is_in_snapshot());
+
let mut errors = Vec::new();
let mut next_round = FxIndexSet::default();
let mut making_progress;
// 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 goal_in_environment = in_environment(infcx, &obligation);
+ let obligation = infcx.resolve_vars_if_possible(&obligation);
+ let environment = obligation.param_env.caller_bounds();
+ let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
let mut orig_values = OriginalQueryValues::default();
- let canonical_goal =
- infcx.canonicalize_query(&goal_in_environment, &mut orig_values);
+ let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values);
match infcx.tcx.evaluate_goal(canonical_goal) {
Ok(response) => {
obligation
)
}
+
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!(
+ span,
+ "TypeWellFormedFromEnv predicate should only exist in the environment"
+ ),
}
}
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert_size!(PendingPredicateObligation<'_>, 64);
+static_assert_size!(PendingPredicateObligation<'_>, 56);
impl<'a, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
obligation.with(pred.to_predicate(self.selcx.tcx())),
]))
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for Chalk")
+ }
},
&ty::PredicateKind::Atom(atom) => match atom {
ty::PredicateAtom::Trait(ref data, _) => {
}
}
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for Chalk")
+ }
},
}
}
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
- let elaborated_env = ty::ParamEnv::new(
- tcx.intern_predicates(&predicates),
- unnormalized_env.reveal(),
- unnormalized_env.def_id,
- );
+ let elaborated_env =
+ ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal());
// HACK: we are trying to normalize the param-env inside *itself*. The problem is that
// normalization expects its param-env to be already normalized, which means we have
let outlives_env: Vec<_> =
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
let outlives_env =
- ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None);
+ ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal());
let outlives_predicates = match do_normalize_predicates(
tcx,
region_context,
let mut predicates = non_outlives_predicates;
predicates.extend(outlives_predicates);
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
- ty::ParamEnv::new(
- tcx.intern_predicates(&predicates),
- unnormalized_env.reveal(),
- unnormalized_env.def_id,
- )
+ ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal())
}
pub fn fully_normalize<'a, 'tcx, T>(
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::Subtype(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => None,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
}
})
.collect()
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::TypeOutlives(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => false,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false,
}
})
}
.chain(iter::once(trait_predicate))
.collect();
- ty::ParamEnv::new(
- tcx.intern_predicates(&caller_bounds),
- param_env.reveal(),
- param_env.def_id,
- )
+ ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal())
};
// Receiver: DispatchFromDyn<Receiver[Self => U]>
}
}
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for chalk")
+ }
}
}
wf.compute(c1.into());
wf.compute(c2.into());
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for Chalk")
+ }
}
wf.normalize()
//! not. To lower anything wrapped in a `Binder`, we first deeply find any bound
//! variables from the current `Binder`.
-use rustc_middle::traits::{
- ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner,
-};
+use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
use rustc_middle::ty::fold::TypeFolder;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{
use std::collections::btree_map::{BTreeMap, Entry};
-use chalk_ir::fold::shift::Shift;
-
/// Essentially an `Into` with a `&RustInterner` parameter
crate trait LowerInto<'tcx, T> {
/// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`.
self,
interner: &RustInterner<'tcx>,
) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
- let clauses = self.environment.into_iter().map(|clause| match clause {
- ChalkEnvironmentClause::Predicate(predicate) => {
- let (predicate, binders, _named_regions) =
- collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx));
- let consequence = match predicate {
- ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
- chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)),
- ),
- ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
- chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
- a: predicate.0.lower_into(interner),
- b: predicate.1.lower_into(interner),
- }),
- ),
- ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
- chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
- ty: predicate.0.lower_into(interner),
- lifetime: predicate.1.lower_into(interner),
- }),
- ),
- ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds(
- chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
- ),
- ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => {
- bug!("unexpected predicate {}", predicate)
- }
- };
- let value = chalk_ir::ProgramClauseImplication {
- consequence,
- conditions: chalk_ir::Goals::empty(interner),
- priority: chalk_ir::ClausePriority::High,
- constraints: chalk_ir::Constraints::empty(interner),
- };
- chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner)
- }
- ChalkEnvironmentClause::TypeFromEnv(ty) => {
- chalk_ir::ProgramClauseData(chalk_ir::Binders::new(
- chalk_ir::VariableKinds::empty(interner),
- chalk_ir::ProgramClauseImplication {
- consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(
- ty.lower_into(interner).shifted_in(interner),
- )),
- conditions: chalk_ir::Goals::empty(interner),
- priority: chalk_ir::ClausePriority::High,
- constraints: chalk_ir::Constraints::empty(interner),
- },
- ))
- .intern(interner)
- }
+ let clauses = self.environment.into_iter().map(|predicate| {
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx));
+ let consequence = match predicate {
+ ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner)))
+ }
+ ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
+ chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)),
+ ),
+ ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+ chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+ a: predicate.0.lower_into(interner),
+ b: predicate.1.lower_into(interner),
+ }),
+ ),
+ ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+ chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
+ ty: predicate.0.lower_into(interner),
+ lifetime: predicate.1.lower_into(interner),
+ }),
+ ),
+ ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds(
+ chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
+ ),
+ ty::PredicateAtom::WellFormed(..)
+ | ty::PredicateAtom::ObjectSafe(..)
+ | ty::PredicateAtom::ClosureKind(..)
+ | ty::PredicateAtom::Subtype(..)
+ | ty::PredicateAtom::ConstEvaluatable(..)
+ | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
+ };
+ let value = chalk_ir::ProgramClauseImplication {
+ consequence,
+ conditions: chalk_ir::Goals::empty(interner),
+ priority: chalk_ir::ClausePriority::High,
+ constraints: chalk_ir::Constraints::empty(interner),
+ };
+ chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner)
});
let goal: chalk_ir::GoalData<RustInterner<'tcx>> = self.goal.lower_into(&interner);
| ty::PredicateAtom::ConstEquate(..) => {
chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
}
+ ty::PredicateAtom::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal(
+ chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))),
+ ),
};
chalk_ir::GoalData::Quantified(
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::Subtype(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", &self),
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ bug!("unexpected predicate {}", &self)
+ }
};
value.map(|value| chalk_ir::Binders::new(binders, value))
}
//! Calls `chalk-solve` to solve a `ty::Predicate`
//!
-//! In order to call `chalk-solve`, this file must convert a
-//! `ChalkCanonicalGoal` into a Chalk ucanonical goal. It then calls Chalk, and
-//! converts the answer back into rustc solution.
+//! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into
+//! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution.
crate mod db;
crate mod lowering;
use rustc_infer::infer::canonical::{
Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
};
-use rustc_infer::traits::{self, ChalkCanonicalGoal};
+use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
use crate::chalk::lowering::{
crate fn evaluate_goal<'tcx>(
tcx: TyCtxt<'tcx>,
- obligation: ChalkCanonicalGoal<'tcx>,
+ obligation: CanonicalChalkEnvironmentAndGoal<'tcx>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> {
let interner = ChalkRustInterner { tcx };
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::ObjectSafe(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => vec![],
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![],
ty::PredicateAtom::WellFormed(arg) => {
wf_args.push(arg);
vec![]
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::Subtype(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => true,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true,
}
}
+use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_infer::traits::util;
use rustc_middle::hir::map as hir_map;
use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{
+ self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
+};
use rustc_session::CrateDisambiguator;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
}
// Compute the bounds on Self and the type parameters.
- let ty::InstantiatedPredicates { predicates, .. } =
+ let ty::InstantiatedPredicates { mut predicates, .. } =
tcx.predicates_of(def_id).instantiate_identity(tcx);
// Finally, we have to normalize the bounds in the environment, in
// 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),
- );
+ if tcx.sess.opts.debugging_opts.chalk {
+ let environment = well_formed_types_in_env(tcx, def_id);
+ predicates.extend(environment);
+ }
+
+ let unnormalized_env =
+ ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
let body_id = def_id
.as_local()
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
}
+/// Elaborate the environment.
+///
+/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s
+/// that are assumed to be well-formed (because they come from the environment).
+///
+/// Used only in chalk mode.
+fn well_formed_types_in_env<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+) -> &'tcx ty::List<Predicate<'tcx>> {
+ use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
+ use rustc_middle::ty::subst::GenericArgKind;
+
+ 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 well_formed_types_in_env(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();
+
+ if !def_id.is_local() {
+ return ty::List::empty();
+ }
+ let hir_id = tcx.hir().local_def_id_to_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 = FxIndexSet::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");
+
+ // FIXME(chalk): this has problems because of late-bound regions
+ //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
+ inputs.extend(trait_ref.substs.iter());
+ }
+
+ // 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 input_clauses = inputs.into_iter().filter_map(|arg| {
+ match arg.unpack() {
+ GenericArgKind::Type(ty) => {
+ let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty));
+ Some(tcx.mk_predicate(PredicateKind::ForAll(binder)))
+ }
+
+ // FIXME(eddyb) no WF conditions from lifetimes?
+ GenericArgKind::Lifetime(_) => None,
+
+ // FIXME(eddyb) support const generics in Chalk
+ GenericArgKind::Const(_) => None,
+ }
+ });
+
+ tcx.mk_predicates(clauses.chain(input_clauses))
+}
+
fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
tcx.param_env(def_id).with_reveal_all_normalized(tcx)
}
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
- let param_env = ty::ParamEnv::new(
- tcx.intern_predicates(&hybrid_preds.predicates),
- Reveal::UserFacing,
- None,
- );
+ let param_env =
+ ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(
tcx,
impl_m.def_id,
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
- let param_env = ty::ParamEnv::new(
- tcx.intern_predicates(&hybrid_preds.predicates),
- Reveal::UserFacing,
- None,
- );
+ let param_env =
+ ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(
tcx,
impl_ty.def_id,
})
.to_predicate(tcx),
);
- ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None)
+ ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
};
tcx.infer_ctxt().enter(move |infcx| {
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::TypeOutlives(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => None,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
},
);
// code is looking for a self type of a unresolved
// inference variable.
ty::PredicateAtom::ClosureKind(..) => None,
+ ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
}
})
.filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
| ty::PredicateAtom::ObjectSafe(_)
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => None,
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
}
}
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::Subtype(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => (),
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (),
}
}
| ty::PredicateAtom::ObjectSafe(..)
| ty::PredicateAtom::ClosureKind(..)
| ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => panic!("not user writable"),
+ | ty::PredicateAtom::ConstEquate(..)
+ | ty::PredicateAtom::TypeWellFormedFromEnv(..) => panic!("not user writable"),
}
}
}
error[E0277]: the trait bound `{float}: Bar` is not satisfied
- --> $DIR/type_inference.rs:27:5
+ --> $DIR/type_inference.rs:27:14
|
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}`
+ | ^ the trait `Bar` is not implemented for `{float}`
|
= help: the following implementations were found:
<i32 as Bar>
| ^^^^^^^^^^
|
= note: ...which again requires computing drop-check constraints for `MList`, completing the cycle
- = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: MList } }`
+ = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }`
error: aborting due to 2 previous errors