diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-01-21 19:42:20 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-01-21 19:42:20 +0100 |
| commit | 3484e2fab4153068e4e5eaebab215e680efe38f1 (patch) | |
| tree | 4955c22b712892f482ee718f954769726fd66baa /src/librustc | |
| parent | d532a04a1c6afb34c8b0ac5da3e2bbf76aad5800 (diff) | |
| parent | 6bd69a10921785aa8ab68e58d9c7a7ea1ff6ef96 (diff) | |
| download | rust-3484e2fab4153068e4e5eaebab215e680efe38f1.tar.gz rust-3484e2fab4153068e4e5eaebab215e680efe38f1.zip | |
Rollup merge of #68140 - ecstatic-morse:const-trait-bound-opt-out, r=oli-obk
Implement `?const` opt-out for trait bounds For now, such bounds are treated exactly the same as unprefixed ones in all contexts. [RFC 2632](https://github.com/rust-lang/rfcs/pull/2632) does not specify whether such bounds are forbidden outside of `const` contexts, so they are allowed at the moment. Prior to this PR, the constness of a trait bound/impl was stored in `TraitRef`. Now, the constness of an `impl` is stored in `ast::ItemKind::Impl` and the constness of a bound in `ast::TraitBoundModifer`. Additionally, constness of trait bounds is now stored in an additional field of `ty::Predicate::Trait`, and the combination of the constness of the item along with any `TraitBoundModifier` determines the constness of the bound in accordance with the RFC. Encoding the constness of impls at the `ty` level is left for a later PR. After a discussion in \#wg-grammar on Discord, it was decided that the grammar should not encode the mutual exclusivity of trait bound modifiers. The grammar for trait bound modifiers remains `[?const] [?]`. To encode this, I add a dummy variant to `ast::TraitBoundModifier` that is used when the syntax `?const ?` appears. This variant causes an error in AST validation and disappears during HIR lowering. cc #67794 r? @oli-obk
Diffstat (limited to 'src/librustc')
| -rw-r--r-- | src/librustc/traits/auto_trait.rs | 9 | ||||
| -rw-r--r-- | src/librustc/traits/engine.rs | 4 | ||||
| -rw-r--r-- | src/librustc/traits/error_reporting/mod.rs | 28 | ||||
| -rw-r--r-- | src/librustc/traits/error_reporting/suggestions.rs | 17 | ||||
| -rw-r--r-- | src/librustc/traits/fulfill.rs | 2 | ||||
| -rw-r--r-- | src/librustc/traits/mod.rs | 4 | ||||
| -rw-r--r-- | src/librustc/traits/object_safety.rs | 10 | ||||
| -rw-r--r-- | src/librustc/traits/project.rs | 11 | ||||
| -rw-r--r-- | src/librustc/traits/query/type_op/prove_predicate.rs | 2 | ||||
| -rw-r--r-- | src/librustc/traits/select.rs | 14 | ||||
| -rw-r--r-- | src/librustc/traits/util.rs | 33 | ||||
| -rw-r--r-- | src/librustc/traits/wf.rs | 14 | ||||
| -rw-r--r-- | src/librustc/ty/fold.rs | 9 | ||||
| -rw-r--r-- | src/librustc/ty/mod.rs | 69 | ||||
| -rw-r--r-- | src/librustc/ty/print/pretty.rs | 7 | ||||
| -rw-r--r-- | src/librustc/ty/structural_impls.rs | 12 | ||||
| -rw-r--r-- | src/librustc/ty/sty.rs | 10 |
17 files changed, 179 insertions, 76 deletions
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs index 89b28aeda1c..c97c5c2077f 100644 --- a/src/librustc/traits/auto_trait.rs +++ b/src/librustc/traits/auto_trait.rs @@ -337,7 +337,10 @@ impl AutoTraitFinder<'tcx> { &Err(SelectionError::Unimplemented) => { if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { already_visited.remove(&pred); - self.add_user_pred(&mut user_computed_preds, ty::Predicate::Trait(pred)); + self.add_user_pred( + &mut user_computed_preds, + ty::Predicate::Trait(pred, ast::Constness::NotConst), + ); predicates.push_back(pred); } else { debug!( @@ -405,7 +408,7 @@ impl AutoTraitFinder<'tcx> { let mut should_add_new = true; user_computed_preds.retain(|&old_pred| { match (&new_pred, old_pred) { - (&ty::Predicate::Trait(new_trait), ty::Predicate::Trait(old_trait)) => { + (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) => { if new_trait.def_id() == old_trait.def_id() { let new_substs = new_trait.skip_binder().trait_ref.substs; let old_substs = old_trait.skip_binder().trait_ref.substs; @@ -627,7 +630,7 @@ impl AutoTraitFinder<'tcx> { // We check this by calling is_of_param on the relevant types // from the various possible predicates match &predicate { - &ty::Predicate::Trait(p) => { + &ty::Predicate::Trait(p, _) => { if self.is_param_no_infer(p.skip_binder().trait_ref.substs) && !only_projections && is_new_pred diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index 5b804480119..84bfc86e6a9 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -1,6 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; -use crate::ty::{self, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_hir::def_id::DefId; use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError}; @@ -33,7 +33,7 @@ pub trait TraitEngine<'tcx>: 'tcx { cause, recursion_depth: 0, param_env, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }, ); } diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs index 646cb80bffd..d1c369d0abb 100644 --- a/src/librustc/traits/error_reporting/mod.rs +++ b/src/librustc/traits/error_reporting/mod.rs @@ -19,7 +19,9 @@ use crate::ty::error::ExpectedFound; use crate::ty::fast_reject; use crate::ty::fold::TypeFolder; use crate::ty::SubtypePredicate; -use crate::ty::{self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{ + self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; @@ -128,7 +130,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) => (cond, error), + (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), _ => { // FIXME: make this work in other cases too. return false; @@ -136,7 +138,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) { - if let ty::Predicate::Trait(implication) = implication { + if let ty::Predicate::Trait(implication, _) = implication { let error = error.to_poly_trait_ref(); let implication = implication.to_poly_trait_ref(); // FIXME: I'm just not taking associated types at all here. @@ -528,7 +530,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return; } match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { + ty::Predicate::Trait(ref trait_predicate, _) => { let trait_predicate = self.resolve_vars_if_possible(trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { @@ -581,7 +583,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{}", message.unwrap_or_else(|| format!( "the trait bound `{}` is not satisfied{}", - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), post_message, )) ); @@ -693,7 +695,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trait_pred }); let unit_obligation = Obligation { - predicate: ty::Predicate::Trait(predicate), + predicate: ty::Predicate::Trait( + predicate, + ast::Constness::NotConst, + ), ..obligation.clone() }; if self.predicate_may_hold(&unit_obligation) { @@ -986,7 +991,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) -> PredicateObligation<'tcx> { let new_trait_ref = ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; - Obligation::new(cause, param_env, new_trait_ref.to_predicate()) + Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) } } @@ -1074,7 +1079,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let mut err = match predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { let trait_ref = data.to_poly_trait_ref(); let self_ty = trait_ref.self_ty(); debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); @@ -1267,8 +1272,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) .value; - let obligation = - Obligation::new(ObligationCause::dummy(), param_env, cleaned_pred.to_predicate()); + let obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + cleaned_pred.without_const().to_predicate(), + ); self.predicate_may_hold(&obligation) }) diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index c18e17581ce..4559007ea42 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -6,7 +6,7 @@ use super::{ use crate::infer::InferCtxt; use crate::traits::object_safety::object_safety_violations; use crate::ty::TypeckTables; -use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_errors::{ error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, @@ -48,7 +48,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } else { " where" }, - trait_ref.to_predicate(), + trait_ref.without_const().to_predicate(), ), Applicability::MachineApplicable, ); @@ -338,8 +338,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty); let substs = self.tcx.mk_substs_trait(new_self_ty, &[]); let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs); - let new_obligation = - Obligation::new(ObligationCause::dummy(), param_env, new_trait_ref.to_predicate()); + let new_obligation = Obligation::new( + ObligationCause::dummy(), + param_env, + new_trait_ref.without_const().to_predicate(), + ); if self.predicate_must_hold_modulo_regions(&new_obligation) { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument @@ -1120,7 +1123,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // the type. The last generator has information about where the bound was introduced. At // least one generator should be present for this diagnostic to be modified. let (mut trait_ref, mut target_ty) = match obligation.predicate { - ty::Predicate::Trait(p) => { + ty::Predicate::Trait(p, _) => { (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) } _ => (None, None), @@ -1543,7 +1546,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note(&format!("required because it appears within the type `{}`", ty)); obligated_types.push(ty); - let parent_predicate = parent_trait_ref.to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(); if !self.is_recursive_obligation(obligated_types, &data.parent_code) { self.note_obligation_cause_code( err, @@ -1560,7 +1563,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { parent_trait_ref.print_only_trait_path(), parent_trait_ref.skip_binder().self_ty() )); - let parent_predicate = parent_trait_ref.to_predicate(); + let parent_predicate = parent_trait_ref.without_const().to_predicate(); self.note_obligation_cause_code( err, &parent_predicate, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 46ece6fc405..0aac6fb81e4 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -311,7 +311,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } match obligation.predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { let trait_obligation = obligation.with(data.clone()); if data.is_global() { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e93529186ac..daaba95cf6b 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -29,7 +29,7 @@ use crate::mir::interpret::ErrorHandled; use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness}; use crate::util::common::ErrorReported; use chalk_engine; use rustc_hir as hir; @@ -732,7 +732,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( param_env, cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID), recursion_depth: 0, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }; let result = infcx.predicate_must_hold_modulo_regions(&obligation); diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index ce57fb81104..15f81bb3f47 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -12,7 +12,7 @@ use super::elaborate_predicates; use crate::traits::{self, Obligation, ObligationCause}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; @@ -234,7 +234,7 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref)) .any(|predicate| { match predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { // In the case of a trait predicate, we can skip the "self" type. data.skip_binder().input_types().skip(1).any(has_self_ty) } @@ -285,7 +285,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; elaborate_predicates(tcx, predicates).any(|predicate| match predicate { - ty::Predicate::Trait(ref trait_pred) => { + ty::Predicate::Trait(ref trait_pred, _) => { trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) } ty::Predicate::Projection(..) @@ -585,6 +585,7 @@ fn receiver_is_dispatchable<'tcx>( def_id: unsize_did, substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), } + .without_const() .to_predicate(); // U: Trait<Arg1, ..., ArgN> @@ -598,7 +599,7 @@ fn receiver_is_dispatchable<'tcx>( } }); - ty::TraitRef { def_id: unsize_did, substs }.to_predicate() + ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate() }; let caller_bounds: Vec<Predicate<'tcx>> = param_env @@ -620,6 +621,7 @@ fn receiver_is_dispatchable<'tcx>( def_id: dispatch_from_dyn_did, substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), } + .without_const() .to_predicate(); Obligation::new(ObligationCause::dummy(), param_env, predicate) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 5bc211ade40..62672a78104 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -16,7 +16,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -738,7 +738,12 @@ fn get_paranoid_cache_value_obligation<'a, 'tcx>( depth: usize, ) -> PredicateObligation<'tcx> { let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - Obligation { cause, recursion_depth: depth, param_env, predicate: trait_ref.to_predicate() } + Obligation { + cause, + recursion_depth: depth, + param_env, + predicate: trait_ref.without_const().to_predicate(), + } } /// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not @@ -772,7 +777,7 @@ fn normalize_to_error<'a, 'tcx>( cause, recursion_depth: depth, param_env, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.without_const().to_predicate(), }; let tcx = selcx.infcx().tcx; let def_id = projection_ty.item_def_id; diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs index c0a0cbe9a38..15870ec95d8 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -24,7 +24,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { // `&T`, accounts for about 60% percentage of the predicates // we have to prove. No need to canonicalize and all that for // such cases. - if let Predicate::Trait(trait_ref) = key.value.predicate { + if let Predicate::Trait(trait_ref, _) = key.value.predicate { if let Some(sized_def_id) = tcx.lang_items().sized_trait() { if trait_ref.def_id() == sized_def_id { if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) { diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3bfe542baab..ac1ca4db9d6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -37,7 +37,7 @@ use crate::middle::lang_items; use crate::ty::fast_reject; use crate::ty::relate::TypeRelation; use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir::def_id::DefId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -51,7 +51,7 @@ use std::cmp; use std::fmt::{self, Display}; use std::iter; use std::rc::Rc; -use syntax::attr; +use syntax::{ast, attr}; pub struct SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, @@ -718,7 +718,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate { - ty::Predicate::Trait(ref t) => { + ty::Predicate::Trait(ref t, _) => { debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(t.clone()); self.evaluate_trait_predicate_recursively(previous_stack, obligation) @@ -945,7 +945,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // trait refs. This is important because it's only a cycle // if the regions match exactly. let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); - let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate)); + let cycle = cycle.map(|stack| { + ty::Predicate::Trait(stack.obligation.predicate, ast::Constness::NotConst) + }); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); Some(EvaluatedToOk) @@ -1060,7 +1062,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { let result = match predicate { - ty::Predicate::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()), + ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), _ => false, }; debug!("coinductive_predicate({:?}) = {:?}", predicate, result); @@ -3366,7 +3368,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tcx.require_lang_item(lang_items::SizedTraitLangItem, None), tcx.mk_substs_trait(source, &[]), ); - nested.push(predicate_to_obligation(tr.to_predicate())); + nested.push(predicate_to_obligation(tr.without_const().to_predicate())); // If the type is `Foo + 'a`, ensure that the type // being cast to `Foo + 'a` outlives `'a`: diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index f058a4d2df2..f3bd98b8551 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -4,7 +4,7 @@ use smallvec::SmallVec; use crate::ty::outlives::Component; use crate::ty::subst::{GenericArg, Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; +use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -13,8 +13,8 @@ use super::{Normalized, Obligation, ObligationCause, PredicateObligation, Select fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { match *pred { - ty::Predicate::Trait(ref data) => { - ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)) + ty::Predicate::Trait(ref data, constness) => { + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) } ty::Predicate::RegionOutlives(ref data) => { @@ -99,14 +99,14 @@ pub fn elaborate_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, ) -> Elaborator<'tcx> { - elaborate_predicates(tcx, vec![trait_ref.to_predicate()]) + elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()]) } pub fn elaborate_trait_refs<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, ) -> Elaborator<'tcx> { - let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect(); + let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect(); elaborate_predicates(tcx, predicates) } @@ -127,7 +127,7 @@ impl Elaborator<'tcx> { fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { let tcx = self.visited.tcx; match *predicate { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); @@ -358,7 +358,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { let tcx = self.tcx; let trait_ref = item.trait_ref(); - let pred = trait_ref.to_predicate(); + let pred = trait_ref.without_const().to_predicate(); debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); @@ -370,13 +370,9 @@ impl<'tcx> TraitAliasExpander<'tcx> { // Don't recurse if this trait alias is already on the stack for the DFS search. let anon_pred = anonymize_predicate(tcx, &pred); - if item - .path - .iter() - .rev() - .skip(1) - .any(|(tr, _)| anonymize_predicate(tcx, &tr.to_predicate()) == anon_pred) - { + if item.path.iter().rev().skip(1).any(|(tr, _)| { + anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred + }) { return false; } @@ -471,7 +467,7 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits< fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { while let Some(pred) = self.base_iterator.next() { - if let ty::Predicate::Trait(data) = pred { + if let ty::Predicate::Trait(data, _) = pred { return Some(data.to_poly_trait_ref()); } } @@ -545,7 +541,12 @@ pub fn predicate_for_trait_ref<'tcx>( trait_ref: ty::TraitRef<'tcx>, recursion_depth: usize, ) -> PredicateObligation<'tcx> { - Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() } + Obligation { + cause, + param_env, + recursion_depth, + predicate: trait_ref.without_const().to_predicate(), + } } pub fn predicate_for_trait_def( diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs index 869ba5315c1..a0cb8446c92 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc/traits/wf.rs @@ -3,7 +3,7 @@ use crate::infer::InferCtxt; use crate::middle::lang_items; use crate::traits::{self, AssocTypeBoundData}; use crate::ty::subst::SubstsRef; -use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Ident}; @@ -62,7 +62,7 @@ pub fn predicate_obligations<'a, 'tcx>( // (*) ok to skip binders, because wf code is prepared for it match *predicate { - ty::Predicate::Trait(ref t) => { + ty::Predicate::Trait(ref t, _) => { wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) } ty::Predicate::RegionOutlives(..) => {} @@ -245,7 +245,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } } - ty::Predicate::Trait(proj) => { + ty::Predicate::Trait(proj, _) => { // An associated item obligation born out of the `trait` failed to be met. // Point at the `impl` that failed the obligation, the associated item that // needed to meet the obligation, and the definition of that associated item, @@ -350,7 +350,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.compute_trait_ref(&trait_ref, Elaborate::None); if !data.has_escaping_bound_vars() { - let predicate = trait_ref.to_predicate(); + let predicate = trait_ref.without_const().to_predicate(); let cause = self.cause(traits::ProjectionWf(data)); self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); } @@ -378,7 +378,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), substs: self.infcx.tcx.mk_substs_trait(subty, &[]), }; - self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + trait_ref.without_const().to_predicate(), + )); } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index b16db6ae5b1..0dddca98c62 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -150,6 +150,15 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } } +impl TypeFoldable<'tcx> for syntax::ast::Constness { + fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { + *self + } + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { + false + } +} + /// The `TypeFolder` trait defines the actual *folding*. There is a /// method defined for every foldable type. Each of these has a /// default implementation that does an "identity" fold. Within each diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3040ecf90ed..0470ab20dc4 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -52,7 +52,7 @@ use std::ops::Deref; use std::ops::Range; use std::slice; use std::{mem, ptr}; -use syntax::ast::{self, Ident, Name, NodeId}; +use syntax::ast::{self, Constness, Ident, Name, NodeId}; use syntax::attr; pub use self::sty::BoundRegion::*; @@ -1068,7 +1068,11 @@ pub enum Predicate<'tcx> { /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. - Trait(PolyTraitPredicate<'tcx>), + /// + /// A trait predicate will have `Constness::Const` if it originates + /// from a bound on a `const fn` without the `?const` opt-out (e.g., + /// `const fn foobar<Foo: Bar>() {}`). + Trait(PolyTraitPredicate<'tcx>, Constness), /// `where 'a: 'b` RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), @@ -1191,8 +1195,8 @@ impl<'tcx> Predicate<'tcx> { let substs = &trait_ref.skip_binder().substs; match *self { - Predicate::Trait(ref binder) => { - Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs))) + Predicate::Trait(ref binder, constness) => { + Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness) } Predicate::Subtype(ref binder) => { Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs))) @@ -1336,15 +1340,33 @@ pub trait ToPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx>; } -impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait( + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + self.constness, + ) + } +} + +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { + fn to_predicate(&self) -> Predicate<'tcx> { + ty::Predicate::Trait( + ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + self.constness, + ) + } +} + +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() })) + ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) } } -impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { +impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.to_poly_trait_predicate()) + ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness) } } @@ -1413,7 +1435,7 @@ impl<'tcx> Predicate<'tcx> { /// with depth 0 are bound by the predicate. pub fn walk_tys(&'a self) -> impl Iterator<Item = Ty<'tcx>> + 'a { match *self { - ty::Predicate::Trait(ref data) => { + ty::Predicate::Trait(ref data, _) => { WalkTysIter::InputTypes(data.skip_binder().input_types()) } ty::Predicate::Subtype(binder) => { @@ -1439,7 +1461,7 @@ impl<'tcx> Predicate<'tcx> { pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> { match *self { - Predicate::Trait(ref t) => Some(t.to_poly_trait_ref()), + Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()), Predicate::Projection(..) | Predicate::Subtype(..) | Predicate::RegionOutlives(..) @@ -1700,6 +1722,33 @@ impl<'tcx> ParamEnv<'tcx> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct ConstnessAnd<T> { + pub constness: Constness, + pub value: T, +} + +// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that +// the constness of trait bounds is being propagated correctly. +pub trait WithConstness: Sized { + #[inline] + fn with_constness(self, constness: Constness) -> ConstnessAnd<Self> { + ConstnessAnd { constness, value: self } + } + + #[inline] + fn with_const(self) -> ConstnessAnd<Self> { + self.with_constness(Constness::Const) + } + + #[inline] + fn without_const(self) -> ConstnessAnd<Self> { + self.with_constness(Constness::NotConst) + } +} + +impl<T> WithConstness for T {} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8b1b2bb5865..9091de55b7d 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1791,7 +1791,12 @@ define_print_and_forward_display! { ty::Predicate<'tcx> { match *self { - ty::Predicate::Trait(ref data) => p!(print(data)), + ty::Predicate::Trait(ref data, constness) => { + if let ast::Constness::Const = constness { + p!(write("const ")); + } + p!(print(data)) + } ty::Predicate::Subtype(ref predicate) => p!(print(predicate)), ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)), ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 62e895af7f3..25f9dc5b0c7 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -15,6 +15,7 @@ use smallvec::SmallVec; use std::fmt; use std::rc::Rc; use std::sync::Arc; +use syntax::ast; impl fmt::Debug for ty::GenericParamDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -234,7 +235,12 @@ impl fmt::Debug for ty::ProjectionPredicate<'tcx> { impl fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - ty::Predicate::Trait(ref a) => a.fmt(f), + ty::Predicate::Trait(ref a, constness) => { + if let ast::Constness::Const = constness { + write!(f, "const ")?; + } + a.fmt(f) + } ty::Predicate::Subtype(ref pair) => pair.fmt(f), ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f), ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f), @@ -474,7 +480,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { type Lifted = ty::Predicate<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { match *self { - ty::Predicate::Trait(ref binder) => tcx.lift(binder).map(ty::Predicate::Trait), + ty::Predicate::Trait(ref binder, constness) => { + tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness)) + } ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype), ty::Predicate::RegionOutlives(ref binder) => { tcx.lift(binder).map(ty::Predicate::RegionOutlives) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 84236128482..13f623aadb1 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -12,7 +12,9 @@ use crate::mir::interpret::Scalar; use crate::mir::Promoted; use crate::ty::layout::VariantIdx; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef}; -use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable}; +use crate::ty::{ + self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness, +}; use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS}; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; @@ -665,14 +667,16 @@ impl<'tcx> Binder<ExistentialPredicate<'tcx>> { pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match *self.skip_binder() { - ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(), + ExistentialPredicate::Trait(tr) => { + Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate() + } ExistentialPredicate::Projection(p) => { ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))) } ExistentialPredicate::AutoTrait(did) => { let trait_ref = Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) }); - trait_ref.to_predicate() + trait_ref.without_const().to_predicate() } } } |
