Skip to content

Commit

Permalink
Rollup merge of rust-lang#68140 - ecstatic-morse:const-trait-bound-op…
Browse files Browse the repository at this point in the history
…t-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](rust-lang/rfcs#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 rust-lang#67794

r? @oli-obk
  • Loading branch information
Centril authored Jan 21, 2020
2 parents d532a04 + 6bd69a1 commit 3484e2f
Show file tree
Hide file tree
Showing 71 changed files with 494 additions and 310 deletions.
9 changes: 6 additions & 3 deletions src/librustc/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/traits/engine.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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(),
},
);
}
Expand Down
28 changes: 18 additions & 10 deletions src/librustc/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -128,15 +130,15 @@ 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;
}
};

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.
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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,
))
);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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())
}
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
})
Expand Down
17 changes: 10 additions & 7 deletions src/librustc/traits/error_reporting/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -48,7 +48,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} else {
" where"
},
trait_ref.to_predicate(),
trait_ref.without_const().to_predicate(),
),
Applicability::MachineApplicable,
);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 6 additions & 4 deletions src/librustc/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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(..)
Expand Down Expand Up @@ -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>
Expand All @@ -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
Expand All @@ -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)
Expand Down
11 changes: 8 additions & 3 deletions src/librustc/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/query/type_op/prove_predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
14 changes: 8 additions & 6 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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>,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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`:
Expand Down
Loading

0 comments on commit 3484e2f

Please sign in to comment.