From 7dad29d6868914484be04cb054863261903bba58 Mon Sep 17 00:00:00 2001 From: Bram van den Heuvel Date: Tue, 1 Sep 2020 17:58:34 +0200 Subject: [PATCH] Remove def_id field from ParamEnv --- .../rustc_infer/src/infer/outlives/mod.rs | 3 +- compiler/rustc_infer/src/traits/mod.rs | 2 +- compiler/rustc_infer/src/traits/util.rs | 3 + compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/chalk.rs | 30 +--- compiler/rustc_middle/src/traits/mod.rs | 6 +- compiler/rustc_middle/src/ty/context.rs | 26 +--- compiler/rustc_middle/src/ty/flags.rs | 3 + compiler/rustc_middle/src/ty/mod.rs | 44 +++--- compiler/rustc_middle/src/ty/print/pretty.rs | 5 + .../rustc_middle/src/ty/structural_impls.rs | 8 +- .../src/transform/qualify_min_const_fn.rs | 3 +- .../rustc_trait_selection/src/opaque_types.rs | 3 +- .../src/traits/auto_trait.rs | 4 +- .../src/traits/chalk_fulfill.rs | 142 ++---------------- .../src/traits/error_reporting/mod.rs | 5 + .../src/traits/fulfill.rs | 8 +- .../rustc_trait_selection/src/traits/mod.rs | 15 +- .../src/traits/object_safety.rs | 12 +- .../src/traits/select/mod.rs | 3 + .../rustc_trait_selection/src/traits/wf.rs | 3 + compiler/rustc_traits/src/chalk/lowering.rs | 107 ++++++------- compiler/rustc_traits/src/chalk/mod.rs | 9 +- .../src/implied_outlives_bounds.rs | 3 +- .../src/normalize_erasing_regions.rs | 3 +- compiler/rustc_ty/src/ty.rs | 135 ++++++++++++++++- .../rustc_typeck/src/check/compare_method.rs | 16 +- .../rustc_typeck/src/check/method/probe.rs | 3 +- compiler/rustc_typeck/src/check/mod.rs | 1 + .../src/impl_wf_check/min_specialization.rs | 3 +- .../rustc_typeck/src/outlives/explicit.rs | 3 +- src/librustdoc/clean/mod.rs | 3 +- src/test/ui/chalkify/type_inference.stderr | 4 +- .../infinite-tag-type-recursion.stderr | 2 +- 35 files changed, 288 insertions(+), 337 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index a1e7f1fa3e5..de98cccf256 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -26,7 +26,8 @@ pub fn explicit_outlives_bounds<'tcx>( | 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)) } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 7e7c8588ffb..a3c4920fa8a 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -57,7 +57,7 @@ pub struct Obligation<'tcx, T> { // `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>; pub type PredicateObligations<'tcx> = Vec>; diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 93fc7f1f3b8..9c0d934a035 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -236,6 +236,9 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) { .map(|predicate| predicate_obligation(predicate, None)), ); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index d18d89ed641..61ecd13c307 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1228,7 +1228,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) | - ConstEquate(..) => continue, + ConstEquate(..) | + TypeWellFormedFromEnv(..) => continue, }; if predicate.is_global() { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 719f0322fd7..15e3110bc85 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1399,7 +1399,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { } query evaluate_goal( - goal: traits::ChalkCanonicalGoal<'tcx> + goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs index 763b078e770..d8507d08c1b 100644 --- a/compiler/rustc_middle/src/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -6,14 +6,11 @@ //! 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}; @@ -376,31 +373,10 @@ impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { 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> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_chalk_environment_clause_list(&v) - } - - fn super_visit_with>(&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>, + pub environment: &'tcx ty::List>, pub goal: ty::Predicate<'tcx>, } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index f86403fa502..ae89b68942c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -26,14 +26,12 @@ 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. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index aa34dedc4b2..aacf61e5b42 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -91,8 +91,6 @@ pub struct CtxtInterners<'tcx> { projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, - - chalk_environment_clause_list: InternedSet<'tcx, List>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -110,7 +108,6 @@ fn new(arena: &'tcx WorkerLocal>) -> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), - chalk_environment_clause_list: Default::default(), } } @@ -2041,7 +2038,7 @@ pub fn $method(self, v: $ty) -> &'tcx $ty { } 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, || { @@ -2060,8 +2057,6 @@ pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { 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> { @@ -2460,13 +2455,6 @@ pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVar 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> { - if ts.is_empty() { List::empty() } else { self._intern_chalk_environment_clause_list(ts) } - } - pub fn mk_fn_sig( self, inputs: I, @@ -2524,18 +2512,6 @@ pub fn mk_substs_trait(self, self_ty: Ty<'tcx>, rest: &[GenericArg<'tcx>]) -> Su 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>, - >, - >( - 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 { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index f7871c4fffd..c9a4022330a 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -249,6 +249,9 @@ fn add_predicate_atom(&mut self, atom: ty::PredicateAtom<'_>) { self.add_const(expected); self.add_const(found); } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + self.add_ty(ty); + } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 29fa3f9bb65..8283deb3ecc 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1155,6 +1155,11 @@ pub enum PredicateAtom<'tcx> { /// 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> { @@ -1450,7 +1455,8 @@ pub fn to_opt_poly_trait_ref(self) -> Option> { | PredicateAtom::ClosureKind(..) | PredicateAtom::TypeOutlives(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } @@ -1465,7 +1471,8 @@ pub fn to_opt_type_outlives(self) -> Option> { | PredicateAtom::ObjectSafe(..) | PredicateAtom::ClosureKind(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } } @@ -1738,11 +1745,6 @@ pub struct ParamEnv<'tcx> { /// /// Note: This is packed, use the reveal() method to access it. packed: CopyTaggedPtr<&'tcx List>, 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, } unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { @@ -1767,7 +1769,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ParamEnv") .field("caller_bounds", &self.caller_bounds()) .field("reveal", &self.reveal()) - .field("def_id", &self.def_id) .finish() } } @@ -1776,23 +1777,16 @@ impl<'a, 'tcx> HashStable> for ParamEnv<'tcx> { 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>(&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>(&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) } } @@ -1803,7 +1797,7 @@ impl<'tcx> ParamEnv<'tcx> { /// type-checking. #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing, None) + Self::new(List::empty(), Reveal::UserFacing) } #[inline] @@ -1825,17 +1819,13 @@ pub fn reveal(self) -> traits::Reveal { /// 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>, - reveal: Reveal, - def_id: Option, - ) -> Self { - ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), def_id } + pub fn new(caller_bounds: &'tcx List>, reveal: Reveal) -> Self { + ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) } } pub fn with_user_facing(mut self) -> Self { @@ -1857,12 +1847,12 @@ pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> 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 diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 538c07b9bde..9562d437914 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2096,6 +2096,11 @@ pub fn print_only_trait_path(self) -> ty::Binder { + p!(write("the type `"), + print(ty), + write("` is found in the environment")) + } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index f8627e2f1b6..afbf805975c 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -260,6 +260,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + write!(f, "TypeWellFormedFromEnv({:?})", ty) + } } } } @@ -536,6 +539,9 @@ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { 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) + } } } } @@ -551,7 +557,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { 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())) } } diff --git a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs index 7d9611e0731..5e102f5151d 100644 --- a/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs +++ b/compiler/rustc_mir/src/transform/qualify_min_const_fn.rs @@ -30,7 +30,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | 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) } diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 9cf3bbd94e0..28697ec4e3b 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -1261,7 +1261,8 @@ pub fn may_define_opaque_type( | 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> diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index ad8e9d9faa6..6b87bc4f34a 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -373,14 +373,12 @@ fn evaluate_predicates( 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 '{:?}' \ diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 0097097707f..adc8ae59086 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -4,12 +4,11 @@ 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>, @@ -21,132 +20,6 @@ impl FulfillmentContext<'tcx> { } } -fn environment<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, -) -> &'tcx ty::List> { - 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, @@ -195,6 +68,8 @@ fn select_where_possible( &mut self, infcx: &InferCtxt<'_, 'tcx>, ) -> Result<(), Vec>> { + assert!(!infcx.is_in_snapshot()); + let mut errors = Vec::new(); let mut next_round = FxIndexSet::default(); let mut making_progress; @@ -205,10 +80,11 @@ fn select_where_possible( // 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) => { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index dcd83798033..a9651144e59 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -663,6 +663,11 @@ fn report_selection_error( obligation ) } + + ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!( + span, + "TypeWellFormedFromEnv predicate should only exist in the environment" + ), } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index a5c6dc042ab..7e505e9c491 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -86,7 +86,7 @@ pub struct PendingPredicateObligation<'tcx> { // `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. @@ -354,6 +354,9 @@ fn process_obligation( 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, _) => { @@ -535,6 +538,9 @@ fn process_obligation( } } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index fe406e88c52..00ca1d0a74a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -301,11 +301,8 @@ pub fn normalize_param_env_or_error<'tcx>( 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 @@ -359,7 +356,7 @@ pub fn normalize_param_env_or_error<'tcx>( 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, @@ -379,11 +376,7 @@ pub fn normalize_param_env_or_error<'tcx>( 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>( diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 6c0c33d3dad..2f2ac9f094d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -276,7 +276,8 @@ fn predicates_reference_self( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } }) .collect() @@ -310,7 +311,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => false, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false, } }) } @@ -654,11 +656,7 @@ fn receiver_is_dispatchable<'tcx>( .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 U]> diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 4258d8e3010..1e1ae78d57d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -592,6 +592,9 @@ fn evaluate_predicate_recursively<'o>( } } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for chalk") + } } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index eb9ee2868f9..998990f374c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -127,6 +127,9 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(c1.into()); wf.compute(c2.into()); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } } wf.normalize() diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index e89a51a8176..650404e8ca6 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -31,9 +31,7 @@ //! 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::{ @@ -43,8 +41,6 @@ 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`. @@ -82,60 +78,45 @@ fn lower_into( self, interner: &RustInterner<'tcx>, ) -> chalk_ir::InEnvironment>> { - 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> = self.goal.lower_into(&interner); @@ -214,6 +195,9 @@ fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData { 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( @@ -684,7 +668,10 @@ fn lower_into( | 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)) } diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index c0d4a5d0e7e..63c5b884357 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -1,8 +1,7 @@ //! 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; @@ -20,7 +19,7 @@ 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::{ @@ -35,7 +34,7 @@ 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 }; diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index de3096eac9b..79308b032ec 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -103,7 +103,8 @@ fn compute_implied_outlives_bounds<'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![] diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 83aee31a39f..3e7c9ac62eb 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => true, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true, } } diff --git a/compiler/rustc_ty/src/ty.rs b/compiler/rustc_ty/src/ty.rs index a0235444ac4..c4b6b64339a 100644 --- a/compiler/rustc_ty/src/ty.rs +++ b/compiler/rustc_ty/src/ty.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -5,7 +6,9 @@ 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; @@ -245,7 +248,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } // 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 @@ -260,11 +263,13 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - let unnormalized_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - traits::Reveal::UserFacing, - tcx.sess.opts.debugging_opts.chalk.then_some(def_id), - ); + 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() @@ -276,6 +281,122 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { 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> { + 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) } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index bbf5153d35d..7aa54e0ebcc 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -202,11 +202,8 @@ fn compare_predicate_entailment<'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, @@ -1120,11 +1117,8 @@ fn compare_type_predicate_entailment<'tcx>( 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, @@ -1227,7 +1221,7 @@ fn compare_projection_bounds<'tcx>( }) .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| { diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 14d80fded71..ebe71b86c92 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -814,7 +814,8 @@ fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, }, ); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index cb5f5731aa6..b95034adb24 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -3918,6 +3918,7 @@ fn obligations_for_self_ty<'b>( // 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)) diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 3746e5778aa..60b9467fca8 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateAtom::ObjectSafe(_) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } } diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs index 135960a4c11..ae336ccca45 100644 --- a/compiler/rustc_typeck/src/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -57,7 +57,8 @@ pub fn explicit_predicates_of( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => (), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1bdbad46755..31d420c3a18 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -508,7 +508,8 @@ fn clean(&self, cx: &DocContext<'_>) -> Option { | 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"), } } } diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index fb8ccbfc660..91c46b95315 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -1,11 +1,11 @@ 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(_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: diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 6d1df4fda2e..45322ea9672 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | = 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