From 01b3637f6e9c01c003f8d9f9bba6d4a6e3c780a9 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 11 Apr 2020 10:23:33 +0200 Subject: [PATCH 1/6] coerce documentation --- src/librustc_infer/infer/at.rs | 1 - src/librustc_typeck/check/coercion.rs | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_infer/infer/at.rs b/src/librustc_infer/infer/at.rs index 5c62a1298b97b..d44b8f554143c 100644 --- a/src/librustc_infer/infer/at.rs +++ b/src/librustc_infer/infer/at.rs @@ -186,7 +186,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a <: b` where `a` may or may not be expected (if /// `a_is_expected` is true, then `a` is expected). - /// Makes `expected <: actual`. pub fn sub(self, a: &T, b: &T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 5d1a1a164855d..e3b16eaaef2a2 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -107,6 +107,7 @@ fn coerce_mutbls<'tcx>( } } +/// Do not require any adjustments, i.e. coerce `x -> x`. fn identity(_: Ty<'_>) -> Vec> { vec![] } @@ -115,6 +116,7 @@ fn simple(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec> move |target| vec![Adjustment { kind, target }] } +/// This always returns `Ok(...)`. fn success<'tcx>( adj: Vec>, target: Ty<'tcx>, @@ -133,6 +135,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } pub fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub); self.commit_if_ok(|_| { if self.use_lub { self.at(&self.cause, self.fcx.param_env).lub(b, a) From a08bccb3c142fb98193eed202dbdde85386dd91a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 11 Apr 2020 18:05:02 +0200 Subject: [PATCH 2/6] handle ByRef in relate --- src/librustc_middle/ty/relate.rs | 36 +++++++++++++++++-- src/test/ui/const-generics/different_byref.rs | 11 ++++++ .../ui/const-generics/different_byref.stderr | 20 +++++++++++ .../const-generics/issues/issue-68615-adt.rs | 11 ++++++ .../issues/issue-68615-array.rs | 11 ++++++ 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/different_byref.rs create mode 100644 src/test/ui/const-generics/different_byref.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68615-adt.rs create mode 100644 src/test/ui/const-generics/issues/issue-68615-array.rs diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index f4f0b6c41b92f..4bfa46367d0c4 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -11,6 +11,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; +use rustc_span::DUMMY_SP; use rustc_target::spec::abi; use std::iter; use std::rc::Rc; @@ -507,6 +508,7 @@ pub fn super_relate_consts>( a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); let eagerly_eval = |x: &'tcx ty::Const<'tcx>| { @@ -561,7 +563,7 @@ pub fn super_relate_consts>( } } - (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => { + (ConstValue::Slice { .. }, ConstValue::Slice { .. }) => { let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); if a_bytes == b_bytes { @@ -571,7 +573,37 @@ pub fn super_relate_consts>( } } - // FIXME(const_generics): handle `ConstValue::ByRef`. + (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { + match a.ty.kind { + ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { + let a_destructured = tcx.destructure_const(relation.param_env().and(a)); + let b_destructured = tcx.destructure_const(relation.param_env().and(b)); + + // Both the variant and each field have to be equal. + if a_destructured.variant == b_destructured.variant { + for (a_field, b_field) in + a_destructured.fields.iter().zip(b_destructured.fields.iter()) + { + relation.consts(a_field, b_field)?; + } + + Ok(a_val) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } + // FIXME(const_generics): There are probably some `TyKind`s + // which should be handled here. + _ => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected consts: a: {:?}, b: {:?}", a, b), + ); + Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))) + } + } + } + _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), }; diff --git a/src/test/ui/const-generics/different_byref.rs b/src/test/ui/const-generics/different_byref.rs new file mode 100644 index 0000000000000..c52a5b8061dbf --- /dev/null +++ b/src/test/ui/const-generics/different_byref.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Const {} + +fn main() { + let mut x = Const::<{ [3] }> {}; + x = Const::<{ [4] }> {}; + //~^ ERROR mismatched types + +} diff --git a/src/test/ui/const-generics/different_byref.stderr b/src/test/ui/const-generics/different_byref.stderr new file mode 100644 index 0000000000000..9ea2aace89aae --- /dev/null +++ b/src/test/ui/const-generics/different_byref.stderr @@ -0,0 +1,20 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/different_byref.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/different_byref.rs:8:9 + | +LL | x = Const::<{ [4] }> {}; + | ^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `4usize` + | + = note: expected struct `Const<[3usize]>` + found struct `Const<[4usize]>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-68615-adt.rs b/src/test/ui/const-generics/issues/issue-68615-adt.rs new file mode 100644 index 0000000000000..140bb28ec5a4f --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-adt.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Const {} +type MyConst = Const<{ [] }>; + +fn main() { + let _x = Const::<{ [] }> {}; + let _y = MyConst {}; +} diff --git a/src/test/ui/const-generics/issues/issue-68615-array.rs b/src/test/ui/const-generics/issues/issue-68615-array.rs new file mode 100644 index 0000000000000..c384bc1e36d02 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-array.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Foo {} + +type MyFoo = Foo<{ [] }>; + +fn main() { + let _ = Foo::<{ [] }> {}; +} From d61debac64af9d9f0c18db55fe66144941aa76c7 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 1 May 2020 19:49:56 +0200 Subject: [PATCH 3/6] Document unsafety for `*const T` and `*mut T` --- src/libcore/ptr/const_ptr.rs | 6 ++++-- src/libcore/ptr/mut_ptr.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 35a0852bbf545..94ad77d1ec683 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -3,8 +3,6 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics; use crate::mem; -// ignore-tidy-undocumented-unsafe - #[lang = "const_ptr"] impl *const T { /// Returns `true` if the pointer is null. @@ -215,6 +213,7 @@ impl *const T { where T: Sized, { + // SAFETY: the `arith_offset` intrinsic has no prerequisites to be called. unsafe { intrinsics::arith_offset(self, count) } } @@ -702,6 +701,7 @@ impl *const T { if !align.is_power_of_two() { panic!("align_offset: align is not a power-of-two"); } + // SAFETY: `align` has been checked to be a power of 2 above unsafe { align_offset(self, align) } } } @@ -729,6 +729,8 @@ impl *const [T] { #[unstable(feature = "slice_ptr_len", issue = "71146")] #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] pub const fn len(self) -> usize { + // SAFETY: this is safe because `*const [T]` and `FatPtr` have the same layout. + // Only `std` can make this guarantee. unsafe { Repr { rust: self }.raw }.len } } diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index dbd92ce5fcc5b..cf9e20aa56941 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -2,8 +2,6 @@ use super::*; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics; -// ignore-tidy-undocumented-unsafe - #[lang = "mut_ptr"] impl *mut T { /// Returns `true` if the pointer is null. @@ -208,6 +206,7 @@ impl *mut T { where T: Sized, { + // SAFETY: the `arith_offset` intrinsic has no prerequisites to be called. unsafe { intrinsics::arith_offset(self, count) as *mut T } } @@ -890,6 +889,7 @@ impl *mut T { if !align.is_power_of_two() { panic!("align_offset: align is not a power-of-two"); } + // SAFETY: `align` has been checked to be a power of 2 above unsafe { align_offset(self, align) } } } @@ -917,6 +917,8 @@ impl *mut [T] { #[unstable(feature = "slice_ptr_len", issue = "71146")] #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] pub const fn len(self) -> usize { + // SAFETY: this is safe because `*const [T]` and `FatPtr` have the same layout. + // Only `std` can make this guarantee. unsafe { Repr { rust_mut: self }.raw }.len } } From e0db42b32fa898cfb0b43b7645c98a45ac05c46b Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Fri, 1 May 2020 20:25:50 +0200 Subject: [PATCH 4/6] doc: reference does not exist, probably a typo --- src/librustc_ast/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 14181e440e96a..415d61743c1e3 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -16,7 +16,7 @@ //! - [`Lit`] and [`LitKind`]: Literal expressions. //! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimeter`]: Macro definition and invocation. //! - [`Attribute`]: Metadata associated with item. -//! - [`UnOp`], [`UnOpKind`], [`BinOp`], [`BinOpKind`]: Unary and binary operators. +//! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. pub use crate::util::parser::ExprPrecedence; pub use GenericArgs::*; From 28f8586698a30ba2e641a2e80594fb423addb5fe Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Fri, 1 May 2020 20:37:34 +0200 Subject: [PATCH 5/6] doc: this resulted in a link pointing to a non-existent target --- src/librustc_ast/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 14181e440e96a..2e068d84f6f6d 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -14,7 +14,7 @@ //! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters. //! - [`EnumDef`] and [`Variant`]: Enum declaration. //! - [`Lit`] and [`LitKind`]: Literal expressions. -//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimeter`]: Macro definition and invocation. +//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimiter`]: Macro definition and invocation. //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`UnOpKind`], [`BinOp`], [`BinOpKind`]: Unary and binary operators. From ef0da3ba4eb5e03d904321bdd8cd8fd3eb8a30e5 Mon Sep 17 00:00:00 2001 From: Jack Huey Date: Fri, 1 May 2020 12:36:18 -0400 Subject: [PATCH 6/6] Remove leftover chalk types --- .../infer/canonical/query_response.rs | 6 +- src/librustc_infer/infer/nll_relate/mod.rs | 13 +- src/librustc_interface/passes.rs | 4 - src/librustc_middle/dep_graph/dep_node.rs | 1 - src/librustc_middle/query/mod.rs | 14 - src/librustc_middle/traits/mod.rs | 158 +---- .../traits/structural_impls.rs | 355 +--------- src/librustc_middle/ty/context.rs | 52 +- src/librustc_middle/ty/query/keys.rs | 12 - src/librustc_middle/ty/query/mod.rs | 1 - src/librustc_middle/ty/relate.rs | 224 ------- src/librustc_middle/ty/subst.rs | 32 - .../borrow_check/type_check/relate_tys.rs | 5 - src/librustc_traits/lib.rs | 2 - src/librustc_traits/lowering/environment.rs | 267 -------- src/librustc_traits/lowering/mod.rs | 627 ------------------ 16 files changed, 5 insertions(+), 1768 deletions(-) delete mode 100644 src/librustc_traits/lowering/environment.rs delete mode 100644 src/librustc_traits/lowering/mod.rs diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index 79a0a5076241f..9fe7ebf58b343 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -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 } diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index 23050a1d5d453..0fb926d94166a 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -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"), } } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 9a8a05713c8d4..7b96d8df12da1 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -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()) diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/src/librustc_middle/dep_graph/dep_node.rs index f4a4aab844c14..d7f3ece83e1df 100644 --- a/src/librustc_middle/dep_graph/dep_node.rs +++ b/src/librustc_middle/dep_graph/dep_node.rs @@ -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, diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index e57c51b9eefbe..b0c442381484c 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -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 { diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index d22a4ac298efe..d6989fd8e4e57 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -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>, } -/// 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>; - -#[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>), - Subtype(Ty<'tcx>, Ty<'tcx>), - CannotProve, -} - -pub type Goal<'tcx> = &'tcx GoalKind<'tcx>; - -pub type Goals<'tcx> = &'tcx List>; - -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>), -} - -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>; - -/// 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(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, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index 5831cb3859f81..69a5213d3e4a5 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -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, - - // Sort by `BoundVar` index, so usually this should be equivalent to the order given - // by the list of type parameters. - types: BTreeMap, - - 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>(&mut self, t: &ty::Binder) -> 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 { - 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 { - 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> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_goals(&v) - } - - fn super_visit_with>(&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>(&self, folder: &mut F) -> Self { - let v = (**self).fold_with(folder); - folder.tcx().mk_goal(v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -CloneTypeFoldableAndLiftImpls! { - traits::ProgramClauseCategory, -} - -impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_clauses(&v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index ae06008d0f9f6..1999a32b3c65b 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -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>>, predicates: InternedSet<'tcx, List>>, - clauses: InternedSet<'tcx, List>>, - goal: InternedSet<'tcx, GoalKind<'tcx>>, - goal_list: InternedSet<'tcx, List>>, projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, 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 for Interned<'tcx, RegionKind> { } } -impl<'tcx> Borrow> for Interned<'tcx, GoalKind<'tcx>> { - fn borrow<'a>(&'a self) -> &'a GoalKind<'tcx> { - &self.0 - } -} - impl<'tcx> Borrow<[ExistentialPredicate<'tcx>]> for Interned<'tcx, List>> { @@ -2014,18 +1998,6 @@ impl<'tcx> Borrow> for Interned<'tcx, Const<'tcx>> { } } -impl<'tcx> Borrow<[Clause<'tcx>]> for Interned<'tcx, List>> { - fn borrow<'a>(&'a self) -> &'a [Clause<'tcx>] { - &self.0[..] - } -} - -impl<'tcx> Borrow<[Goal<'tcx>]> for Interned<'tcx, List>> { - 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( 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], Clauses<'tcx>>>(self, iter: I) -> I::Output { - iter.intern_with(|xs| self.intern_clauses(xs)) - } - - pub fn mk_goals], 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 { diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs index 7354e89001cec..239691dbd17ac 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/src/librustc_middle/ty/query/keys.rs @@ -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; diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs index 899479e65a732..67c84c330b8ed 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/src/librustc_middle/ty/query/mod.rs @@ -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}; diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index f4f0b6c41b92f..c14d8da5b9f51 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -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}; @@ -754,229 +753,6 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { } } -impl<'tcx> Relate<'tcx> for traits::WhereClause<'tcx> { - fn relate>( - 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>( - 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>( - 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>( - 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>( - 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>( - 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>( - 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>( - 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>( - 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>( - 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>( - 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 diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs index 0f4485a705046..4d73f8f91ad2e 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/src/librustc_middle/ty/subst.rs @@ -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 diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index b9a76057d51f8..96ae534c3963f 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -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 } diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index ba840c283b84b..e0533b11ecf00 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -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); diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs deleted file mode 100644 index e7fa245fd4055..0000000000000 --- a/src/librustc_traits/lowering/environment.rs +++ /dev/null @@ -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>, -} - -impl ClauseVisitor<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, round: &'a mut FxHashSet>) -> 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) } -} diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs deleted file mode 100644 index 19765c36ae26a..0000000000000 --- a/src/librustc_traits/lowering/mod.rs +++ /dev/null @@ -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 { - /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk-like type. - fn lower(&self) -> T; -} - -impl Lower> for Vec -where - T: Lower, -{ - fn lower(&self) -> Vec { - self.iter().map(|item| item.lower()).collect() - } -} - -impl<'tcx> Lower> for ty::TraitPredicate<'tcx> { - fn lower(&self) -> WhereClause<'tcx> { - WhereClause::Implemented(*self) - } -} - -impl<'tcx> Lower> for ty::ProjectionPredicate<'tcx> { - fn lower(&self) -> WhereClause<'tcx> { - WhereClause::ProjectionEq(*self) - } -} - -impl<'tcx> Lower> for ty::RegionOutlivesPredicate<'tcx> { - fn lower(&self) -> WhereClause<'tcx> { - WhereClause::RegionOutlives(*self) - } -} - -impl<'tcx> Lower> for ty::TypeOutlivesPredicate<'tcx> { - fn lower(&self) -> WhereClause<'tcx> { - WhereClause::TypeOutlives(*self) - } -} - -impl<'tcx, T> Lower> for T -where - T: Lower>, -{ - 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))` 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`. -impl<'tcx, T> Lower> for ty::Binder -where - T: Lower> + ty::fold::TypeFoldable<'tcx>, -{ - fn lower(&self) -> PolyDomainGoal<'tcx> { - self.map_bound_ref(|p| p.lower()) - } -} - -impl<'tcx> Lower> 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 where WC { .. } // P0 == Self` - - // Rule Implemented-From-Env (see rustc dev guide) - // - // ``` - // forall { - // Implemented(Self: Trait) :- FromEnv(Self: Trait) - // } - // ``` - - let bound_vars = InternalSubsts::bound_vars_for_item(tcx, def_id); - - // `Self: Trait` - let trait_pred = ty::TraitPredicate { trait_ref: ty::TraitRef { def_id, substs: bound_vars } }; - - // `Implemented(Self: Trait)` - let impl_trait: DomainGoal<'_> = trait_pred.lower(); - - // `FromEnv(Self: Trait)` - 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) :- FromEnv(Self: Trait)` - 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::>(); - - // Rule Implied-Bound-From-Trait - // - // For each where clause WC: - // ``` - // forall { - // FromEnv(WC) :- FromEnv(Self: Trait)`, for each where clause WC - let implied_bound_clauses = where_clauses - .iter() - .cloned() - // `FromEnv(WC) :- FromEnv(Self: Trait)` - .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 { - // WellFormed(Self: Trait) :- Implemented(Self: Trait) && 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) :- Implemented(Self: Trait) && 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 Trait for A0 where WC { .. }` - // - // ``` - // forall { - // Implemented(A0: Trait) :- 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)` - 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) :- 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 where WC1, ..., WCm` - // - // ``` - // forall { - // 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::>(); - - // `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 { - // 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 { - // type AssocType; - // } - // ``` - // - // `ProjectionEq` can succeed by skolemizing, see "associated type" - // chapter for more: - // ``` - // forall { - // ProjectionEq( - // >::AssocType = - // (Trait::AssocType) - // ) - // } - // ``` - - 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 { - // WellFormed((Trait::AssocType)) - // :- WellFormed(Self: Trait) - // } - // ``` - - 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 { - // FromEnv(Self: Trait) - // :- FromEnv((Trait::AssocType)) - // } - // ``` - - 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 { - // ProjectionEq(>::AssocType = U) :- - // Normalize(>::AssocType -> 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(>::AssocType = U)` - let projection = ty::ProjectionPredicate { projection_ty, ty: tcx.mk_ty(ty_var) }; - - // `Normalize(>::AssocType -> U)` - let hypothesis = tcx.mk_goal(DomainGoal::Normalize(projection).into_goal()); - - // ProjectionEq(>::AssocType = U) :- - // Normalize(>::AssocType -> 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 Trait for A0 { - // type AssocType = 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 where T: Sized`). - // ``` - // forall { - // forall { - // Normalize(>::AssocType -> T) :- - // Implemented(A0: Trait) - // } - // } - // ``` - - 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` - 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)` - let trait_implemented: DomainGoal<'_> = ty::TraitPredicate { trait_ref }.lower(); - - // `>::AssocType` - let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.ident); - - // `Normalize(>::AssocType -> 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 { - 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); - } -}